Archive/꼼꼼한 재은씨 시리즈

Alamofire 라이브러리 ( + CocoaPods 개념) 설치 및 사용법

lgvv 2021. 4. 23. 11:38

Alamofire는 HTTP 네트워킹을 위해 스위프트 기반으로 개발된 비동기 라이브러리로, URLRequest + URLSession 객체를 래핑한 간결한 구성 덕분에 모바일 서버와 HTTP통신을 구현할 때 많이 사용됩니다. 모바일 API 호출 역시 Alamofire를 이용하면 더 쉽고 간결하게 작성할 수 있습니다.

 

장점은 서버로 보낼 요청을 간편하게 구성 가능

서버의 응답 컨텐츠 타입에 맞추어 사용 가능한 다양한 메소드 제공

예를들면 JSON 데이터를 주고 받기 위한 전용 메소드라던가, 바이너리 파일을 주고 받기 위한 전용 메소드, 대용량 파일을 내려받기 위한 다운로드 메소드 등

특히 JSON 전용 메소드를 이용하면 서버로부터 받은 결과값을 손쉽게 파싱할 수 있다.

또한 다운로드 메소드에서는 다운로드 진행 정보를 함께 제공하기 때문에 이를 이용하면 사용자에게 다운로드 과정을 중계할 수도 있다.

 

 

사용법

1. Xcode 메뉴에서 [Source Control] --> [Clone] 선택

2. https://github.com/Alamofire/Alamofire.git 입력하여 내려받기

3. 저장위치를 선택하여 프로젝트를 생성

--> 이때 저장위치는 앱 프로젝트의 하위로 잡아주는 것이 좋은데 왜냐하면 라이브러리 파일을 직접 복사해도 가능하지만 타깃 의존성 설정을 통해 앱 컴파일 시 자동으로 Alamofire라이브러리가 포함되게 할 예정이라 이 연결은 동적이어서 프로젝트가 진행되는 동안 삭제되거나 옮겨져서는 안되기 때문이다. ** 이를 Alamofire 라이브러리를 기존 프로젝트에 서브 모듈로 설치한다 라고 표한한다.

ex)

   appFolder

        - Alamofire

        - my-app

        - my-app.xcodeproj

4. 동적으로 연결하기 위해 기존 프로젝트에 연결하고 타깃 의존성을 설정해야 하는데 생성된 Alamofire 프로젝트를 탐색기로 열고, Alamofire.xcodeproj 파일을 기존 프로젝트에 드래그 하여 추가한다.

5. 타깃의존성 설정을 위해

 5-1) Xcode 네비게이터에서 내가 진행하고자 하는 프로젝트를 선택

 5-2) 중앙의 편집창 좌측 패널에서 TARGETS 영역의 파일을 선택

 5-3) Builds Phases를 선택

 5-4) Dependencies 항목의 내부에서 [+]를 클릭하여 내가 만드는 것의 특성에 맞게 (ios,macos 등) 선택하여 추가

6. 이후에 viewController.swift 에 import Alamofire 작성 후 커맨티+b 를 통하여 빌드가 성공적으로 이루어 지는지 확인.

 

 

다른 방법으로도 설치하는 방법이 있는데 CocoaPods에 대해서 알아보고 가자

CocoaPods이란? 코코아 프로젝트에 대한 의존성 패키지를 관리하는 도구다. 쉽게 말해서 외부 라이브러리를 간단하게 설치할 수 있게 도와주는 유틸!

과거에는 개발자가 외부라이브러리를 사용하면 자동 업데이트가 이루어지지 않았기 때문에 버전 관리는 순전히 개발자의 성실성에 달려 있었다. 해당 라이브러리의 새 버전으로 업뎃하기 위해서는 개발자가 꾸준히 관심을 갖고 버전 업데이트 여부를 확인해야 했다. 간혹 소홀할 경우 버그가 발생하기도 했다.

 

최근에는 이런 문제를 줄이고 개발 생산성 향상을 위해 주요 라이브러리를 데이터베이스화하여 관리해주는 도구들이 많이 생겨났는데, 우리는 이 유틸을 사용하여 앱 프로젝트에 원하는 라이브러리를 손쉽게 설치하고 버전까지 관리할 수 있게 되었는데, 이것을 패키지 관리 도구 라고 부른다.

 

대표적인 패키지 관리도구는 CentOS 계열의 리눅스에서 사용하는 yum, Fedora 계열의 리눅스에서 사용하는 apt-get, 파이썬 패키지를 관리하는 pip, 루비 패키지를 관리하는 gem, node.js 패키지를 관리하는 npm, 자바의 MAVEN 등이 있다. 이들은 내부적으로 데이터베이스화한 라이브러리 목록을 제공하고 있으며, 이중에서 원하는 라이브러리를 검색하여 간편하게 설치할 수 있다.

 

애플 개발환경에서는 코코아팟을 제외하고 2개가 더 있는데,

Carthage와 스위프트 패키지 관리자 (Swift Package Manager , SPM) 이다.

 

코코아팟은 루비 언어를 이용하여 만들어진 패키지 의존성 관리 도구로서, 지원하는 라이브러리들은 Pod이라는 개념으로 다룬다. 따라서 코코아팟이라는 이름은 코코아 개발환경 + 라이브러리들이라는 의미를 나타내는 것이다.

 

자 그럼 CocoaPod을 이용하여 설치해볼까? 우선 앞선 방법으로 설치했다면 Alamofire.xcodeproj 을 MoveTrash로 삭제하고 폴더를 열어서 Alamofire를 지운다음에 실행해보자

 

설치순서

1. 터미널을 열어서 sudo gem install cocoapods 

sude : root 권한으로 실행하라

gem : 루비 언어에서 사용하는 의존성 패키지 관리 도구를 실행하라

install cocoapods : 코코아팟을 설치하라는 옵션 gem은 macOS에 기본으로 포함되어 있기 때문에 설치 과정 없이 바로 사용 가능

** 간혹 맥을 처음 설치해서 그대로 사용할 경우 루트 패스워드가 설정되지 않을 수도 있다. 이 경우에는 루트 패스워드를 설정하는 과정이 선행되어야 한다.

2. 다음은 Alamofire 라이브러리를 설치하는 것

 2-1) 우선 터미널에서 cd 를 이용하여 내 프로젝트 폴더로 이동한다.

 2-2) 프로젝트 폴더로 이동했으면 pod init 을 터미널에 입력한다.

 2-3) vi Podfile 로 편집기 열고

 2-4) 아래의 코드를 추가한다.

사이트에서 README 파일의 버전을 참조해야한다.

2-5) pod install 입력한다.

    ** 만약 설치시 오류가 발생한다면 코코아팟 데이터베이스에 문제가 있는 경우이므로 pod repo update 통해서 해결할 수도 있다.

2-6) 설치 과정이 끝나면 *.xcworkspace 파일과 함께 Pods 폴더 그리고 Podfile 관련 파일들이 추가되어있다.

3. *.xcworkspace 열어서 작업한다.

주의할 점 : 코코아팟 라이브러리를 설치한 경우 Xcode의 실행 파일이 변경된다. *.xcodeproj 대신에 *.xcworkspace 파일을 사용해야 한다. 기존의 xcodeproj 파일을 사용해서 빌드시 컴파일 오류가 발생한다. 

 

 

 

자 그럼 기본 코드에 대해서 알아보자.

 

Request

import Alamofire // import 먼저 하기

Alamofire.request("호출 URL") // HTTP의 기본값은 GET 방식

Alamofire.request("호출 URL", method: .post) // POST 방식으로 전송하고 싶다면 인자값 추가

/*
 전달해야 할 값이 있을 경우에는 세 번째 매개변수인 parameters를 사용하면 된다. 
 이 변수는 키-값 형식의 타입을 기반으로 한다.
*/
let param : Parameters = [
	"userId" : "lgvv",
    "name" : "h한글"
]

/*
 전달하는 값에 특수문자나 한글 등이 포함되어 있을 경우
 서버에서 잘못 받아들이지 않도록 인코딩 과정을 거쳐야 하는데,
 이떄 request 메소드의 네 번째 매개변수 encoding이 사용된다.
*/
Alamofire.request("호출 URL", method: .post, parameters : param, encoding : URLEncodeing.httpbody)

/*
 매개변수 encoding은 프로토콜인 ParameterEncoding 타입으로, 
 이 프로토콜을 구현한 열거형이나 구조체 또는 클래스 객체를 인자값으로 입력받을 수 있다.
 대표적으로 사용하는 것이 URLEncoding 구조체로, 이 구조체에는 다음과 같은 세가지 인코딩 타입의 
 정적 변수로 선언되어 있다.
 
 .methodDependent : 메소드에 따라 인코딩 타입이 자동으로 결정됨.
 가령 GET방식이면 .queryString
 POST 방식이면 .httpbody가 적용된다.
 
 .queryString : GET 전송에서 사용되는 쿼리 스트링 방식으로 인코딩한다.
 
 .httpbody : POST 전송에서 사용되는 HTTP body 방식으로 인코딩한다.
 
 만약 .httpbody 타입을 적용하면 Content-Type 헤더에는 자동으로 
 'application/x-www-form-urlencoded;charset=utf-8' 이 적용된다
*/
 JSON 방식으로 값을 전송할 때에는 인코딩 타입으로 URLEncoding 대신 JSONEncoding을 사용해야 한다. 
(예시구문)
let param : Parameters = [
	"userId" : "lgvv",
    "name" : "한글2"
]
Alamofire.request("호출 URL", method: .post, parameters : param, encoding : JSONEncoding.default)

//Content-Type 헤더에 'application/json' 값이 자동으로 설정된다.
//Content-Length 헤더 역시 파라미터 인자값과 인코딩 설정을 참고하여 Alamofire 라이브러리가 자동으로 계산한다.

//HTTP 메시지에 별도의 헤더를 추가하고 싶을 경우 headers 매개변수를 사용하면 된다.
//이것도 역시 딕셔너리 형식을 따른다.
(예시구문)
let headers: HTTPHeaders = [
	"Authorization" : "Basic QWxhZGRpbjpvcGVuIHNc2FtZQ==",
    "Accept" : "application/json"   
]
Alamofire.request("호출 URL", method: .post, parameters : param, encoding : JSONEncoding.default, headers : headers)

 

 

Response  Alamofire는 서버의 응답 메시지 처리를 지원하기 위해 다음과 같은 응답 처리 메소드를 제공한다.
response() 응답 메시지에 특별한 처리를 하지 않음.
기본 형태이지만 URLSession 객체를 직접 사용하는 것과 별반 차이가 없으므로 특별한 경우가 아니라면 사용되지 않는다.
responseString() 응답 메시지 본문을 문자열로 처리한 후 전달
responseJSON() 응답 메시지 본문을 JSON 객체로 변환하여 전달
responseData() 응답 메시지 본문을 바이너리 데이터로 변환하여 전달

 

Alamofire는 비동기 기반으로 네트워크 응답을 처리하기 때문에 응답 메시지를 response 메소드의 결과값으로 반환받을 수 없다. 그에 대한 대안으로 우리는 서버로부터 응답이 도착했을 때 실행할 로직을 클로저로 미리 작성하여 위 메소드의 인자값으로 넣어 주어야 하는데 일종의 콜백 함수다.

Alamofire는 서버에서 응답이 도착하면 이를 DataResponse 타입의 객체로 처리한 다음, 이를 클로저의 매개변수에 담아 호출한다. 우리는 이 객체를 활용하여 원하는 값을 추출할 수 있다.

//Response 예시코드

// GET 방식
let url = "http://~~"
AF.request(url).responseString() { response in
	// response에 있는건 api의 세부 문서를 확인해 봐야 한다.
	print("\(reponse.result.isSuccess)")
   	print("\(reponse.result.value!)")
}

// POST 방식

let url = "http://~~"

let param : Parameters = [
	"userId" : "lgvv",
    "name" : "gw"
]

let alamo = AF.request(url, method: .post, parameters : param, encoding : URLEncoding.httpBody)

alamo.responseJSON() { response in
	// response에 있는건 api의 세부 문서를 확인해 봐야 한다.
	print("JSON = \(try! reponse.result.get())")
   	if let jsonObject = try! response.result.get() as? [String:Any] {
    	print("uesrId = \(jsonObject["uesrId"]!)")
        print("name = \(jsonObject["name"]!)")
}

// 실행결과
JSON = {
	name = "\Uc7ac\Uc740\Uc528";
    result = SUCCESS;
    timestamp = "2020-04-23 12:41:22";
    userId = lgvv;
}
userId = lgvv
name = gw

/*
 echo API를 호출하여 얻은 결과
*/