처음부터 차근차근
OpenAPI 사용해서 앱만들기 본문
사전 지식
1급 객체(first class object), 1급 시민(first class citizen)
Swift의 함수는 1급 객체이다.
1급 객체의 조건
1) 변수에 저장할 수 있다.
func inchesToFeet (inches: Float) -> Float {
return inches * 0.0833333
}
let toFeet = inchesToFeet
print(toFeet(10))
2) 매개변수로 전달할 수 있다.
func inchesToFeet (inches: Float) -> Float {
return inches * 0.0833333
}
func outputConversion(converterFunc: (Float) -> Float, value: Float) {//함수를 매개변수로 사용
let result = converterFunc(value) //toFeet(10)
print("Result = \(result)")
}
outputConversion(converterFunc:toFeet, value: 10)
3) 리턴값으로 사용할 수 있다.
func inchesToFeet (inches: Float) -> Float {
return inches * 0.0833333
}
func inchesToYards (inches: Float) -> Float {
return inches * 0.0277778
}
func decideFunction (feet: Bool) -> (Float) -> Float { //매개변수형 리턴형이 함수형
if feet {
return toFeet //함수를 리턴
} else {
return toYards
}
}
let myFunc = decideFunction(feet: true)
클로저(closure)
func add(x: Int, y: Int) -> Int {
return(x+y)
}
// 클로저
let add1 = { (x: Int, y: Int) -> Int in
return(x+y)
}
후행 클로저(trailing closure)
클로저가 함수의 마지막 argument라면 마지막 매개변수명을 생략한 후 함수 소괄호 외부에 클로저를 작성한다.
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
// 클로저 구현
func math(x: Int, y: Int, cal: {(val1: Int, val2: Int) -> Int in
return val1 + val2
})
// 후행 클로저
func math(x: Int, y: Int) {(val1: Int, val2: Int) -> Int in
return val1 + val2
})
OpenAPI 사용
1. movieURL지정과 데이터 가져올 메서드 지정하고 호출
필자의 경우 영화진흥위원회 Open API를 사용함
let movieURL = "https://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=자신이발급받은키&targetDt=20220530"
주의 사항 : http를 https로 변경해야함
2. 네트워킹
1) URL 만들기
failable initializer이므로 url을 옵셔널 바인딩
2) URLSession 만들기
3) URLSession 인스턴스에게 task주기
dataTask(with:completionHandler:)
지정된 URL의 내용을 검색하는 작업을 만든(create) 다음, 완료시 handler(클로저)를 호출
4) task시작하기( task.resume() )
task.resume()
작업이 일시 중단된(새로 초기화된 작업) 경우 다시 시작하는 메서드
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
table.delegate = self
table.dataSource = self
//movieURL += makeYesterdayString()
getData()
}
func getData() {
guard let url = URL(string: movieURL) else {return} // URL 만들기
let session = URLSession(configuration: .default) // URL Session 만들기
// URLSession 인스턴스에게 task주기
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
guard let JSONdata = data else { return }
let dataString = String(data: JSONdata, encoding: .utf8)
print(dataString!) //data를 String형식으로 찍어 보기
}
task.resume()
}
3. 파싱을 쉽게 하기 위한 MovieData형 구조체 만들기
리턴되는 json의 형태가 이미지와 같으므로 아래의 구조체를 만든다.
struct MovieData : Codable {
let boxOfficeResult : BoxOfficeResult
}
struct BoxOfficeResult : Codable {
let dailyBoxOfficeList : [DailyBoxOfficeList]
}
struct DailyBoxOfficeList : Codable {
let movieNm : String
let audiCnt : String
let audiAcc : String
}
moviewNm : 영화명
audioCnt : 해당일의 관객수
audioAcc : 누적 관객수
4. JSONDecoder 객체 만들고, decode 함수 예외처리해서 호출.
그리고 MovieData형 프로퍼티 만들어 decodedData 저장
var movieData : MovieData?
func getData() {
guard let url = URL(string: movieURL) else {return}
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
guard let JSONdata = data else { return }
let dataString = String(data: JSONdata, encoding: .utf8)
print(dataString!)
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MovieData.self, from: JSONdata)
self.movieData = decodedData
DispatchQueue.main.async {
self.table.reloadData()
}
}catch{
print(error)
}
}
task.resume()
}
JSONDecoder : JSON객체에서 데이터 타입의 인스턴스를 디코딩하는 객체
func decode(_ type: T.Type, from data: Data) throws -> T where T : Decodable
static metatype : .self
String이 type이고 ”Hello”가 instance의 value
String.Type은 type이고 String.self가 metatype의 value
.self는 static metatype이고 compile time에서의 object type
reloadData() : 테이블 뷰의 row과 section을 다시 로드
DispatchQueue.main.async { } :
앱의 기본 스레드(메인 스레드) 또는 백그라운드 스레드에서 작업 실행을 순차 또는 동시 처리로 관리하는 개체
현재 프로세스의 main 스레드와 관련된 디스패치 큐
UI관련 소스는 main thread에서 처리해야하기 때문에 이 함수를 사용한다!
예외처리(exception handling)
런타임 시 오류를 발견하여 응답하고 복구하는 과정이다.
작업이 실패할 때 코드가 적절히 응답할 수 있도록 함으로써 오류의 원인을 이해하는 데 도움을 줄 수 있다.
오류의 원인에 따라 다양한 대응이 필요한 경우, 오류의 정보를 정확히 전달함으로써 오류를 복구하는데 도움을 줄 수 있다.
ex) 디스크상의 파일을 읽어서 처리하는 작업에서 발생할 수 있는 오류 ('존재하지 않는 파일', '읽기 권한 없음', '호환되는 형식이 아님' 등 다양)
Swift 2.0 이후부터 error handling을 도입했다.
오류 처리 4가지 방법
- Throwing Functions을 이용한 오류 전파(Propagating Errors Using Throwing Functions)
- Do-Catch를 이용한 오류 처리(Handling Errors Using Do-Catch)
- Error를 Optional Values로 변환(Converting Errors to Optional Values
- 오류 전파 비활성화(Disabling Error Propagation)
throwing function
func add(_ number: Int) throws -> Int { // 1
guard number > 0 else {
throw TestError.outOfRange // 2
}
return number + 1
}
To indicate that a function, method, or initializer can throw an error,
you write the throws keyword in the function’s declaration after its parameters.
함수, 메서드 또는 이니셜라이저가 오류를 던질 수 있음을 나타내려면,
함수 선언에서 매개변수 뒤에 throw 키워드를 작성합니다.
do~try~catch
do {
try 오류 발생 코드
오류가 발생하지 않으면 실행할 코드
} catch 오류패턴1 {
처리 코드
} catch 오류패턴2 where 조건 {
처리 코드
} catch {
처리 코드
}
Label 디자인 변경시 : Resolve Auto Layout Issues
바뀐 것으로 업데이트 인터페이스빌더가 제안 모든 제약 삭제
Selected Views vs All Views in View Controller
가장 쉬운 방법: Clear후 Reset
개선 : 앱을 실행하면 어제 날짜로 자동 조회하기
var movieData : MovieData?
var movieURL = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=3c47a88b3298a90aabde4fef7b450779&targetDt=20220522"
@IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
table.dataSource = self
movieURL += makeYesterdayString()
getData()
}
func makeYesterdayString() -> String {
let y = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
let dateF = DateFormatter()
dateF.dateFormat = "yyyyMMdd"
let day = dateF.string(from: y)
return day
}
출처 : iOS프로그래밍실무(22-1학기)한성현교수 강의 내용 변형 및 요약
'프로그래밍 > Swift' 카테고리의 다른 글
RESTful과 OpenAPI (0) | 2022.05.16 |
---|---|
TableView (0) | 2022.05.13 |
Swift 용어 정리 (0) | 2022.05.09 |
간단한 앱 만들기 실습 (0) | 2022.04.16 |
Swift 문법 복습5 (0) | 2022.04.11 |