今日からswift
を使ったiOSアプリ開発を勉強していきます!
swift
の文法もまだ全然覚えてないが、とりあえず機能を実装しながら習っていきたいと思う。(グーグル頼り)
webエンジニア出身なので、とりあえずswift
でリモートのJSONをパースしてModelに変換してみる。
Gloss(https://github.com/hkellaway/Gloss)という便利なフレームワークもあるようだが、swiftに関して自分はかなり初心者なので、とりあえずswiftだけでやってみる。
JSONはこんな感じ
エンドポイントはhttp://zoo.dev/api
とする(ローカルサーバ)
{
"state": "ok",
"data": {
"entries": [
{
"title": "Title1",
"body": "body1",
"published_at": "2017-10-11 15:00:00"
},
{
"title": "Title2",
"body": "body2",
"published_at": "2017-10-18 15:00:00"
}
]
}
}
まずEntry
というデータ構造を作る:
下記の内容でModel/Entry.swift
を作成:
import Foundation
struct Entry
{
let name: String
let body: String
let published_at: Date? // `?`マークはnilの可能性もあるってこと
public init?(json: [String:Any]) {
self.name = json["title"] as! String
self.body = json["body"] as! String
// 時間の文字列をDate型に変換
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-DD HH:mm:ss"
let published_at_str = json["published_at"] as! String;
self.published_at = dateFormatter.date(from: published_at_str)
}
}
swiftの文法ってすごい直感的で、プログラミングの経験者なら少しでも読めると思う。ちょっと特別なのは、init
というメソード、名前の通り初期化用のメソードである。
エンドポイントにリクエストを出す
swiftでHttpリクエストを出す方法はこのリンクhttps://stackoverflow.com/questions/43047016/urlsession-shared-datatask-with-body-payloadを参考した:
// エラーの種類を定義
enum JSONError : Error {
case invalid // 不正のJSON
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let api_endpoint = URL(string: "http://zoo.dev/api")
let task = URLSession.shared.dataTask(with: api_endpoint!) {(data, response, error) in
do {
let json_str = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)!
print(json_str) // JSON文字列を出してみる
guard let json = try? JSONSerialization.jsonObject(with: data!) as? [String: Any] else {
throw JSONError.invalid
}
guard let root = json?["data"] as? [String: Any],
let entry_json_arr = root["entries"] as? [[String: Any]] else {
throw JSONError.invalid
}
// JSONデータをEntry型に変換
let entries = entry_json_arr.map{(json: [String: Any]) -> Entry in
return Entry(json: json)!
}
for entry in entries {
print(entry)
}
} catch JSONError.invalid {
print("invalid json format")
} catch let error as NSError {
print(error.debugDescription)
}
}
task.resume()
}
...
実行すると:
{"state":"ok","data":{"entries":[{"title":"Title1","body":"body1","published_at":"2017-10-11 15:00:00"},{"title":"Title2","body":"body2","published_at":"2017-10-18 15:00:00"}]}}
Entry(name: "Title1", body: "body1", published_at: Optional(2017-01-11 06:00:00 +0000))
Entry(name: "Title2", body: "body2", published_at: Optional(2017-01-18 06:00:00 +0000))
print
はオブジェクトも綺麗にプリントアウトしてくるのが嬉しい!
で、ここまでちょっと面白いと思うのは:
1. swiftでのエラー処理(throwとcatch)
swift
でエラー処理するには、まず下記のようにenum
型でError
を継承する:
enum CustomError : Error {
case ops
case errorType1
case errorType2
}
ロジック部分をdo { ... } catch { ... }
で例外をキャッチし、処理する:
do {
// ...エラーが出るかもしれない処理
// throw CustomError.errorType1
} catch CustomError.errorType1 {
// errorType1の処理
} catch CustomError.errorType2 {
// errorType2の処理
} catch error as NSError {
// それ以外のエラー
}
2. guard
guard
は何かの原因で処理を失敗し、フォールバックを提供するに使える便利なキーワード。PHPでいうとtry { ... } catch (\Exception $e) { ... }
に近い。構文は下記のように:
guard ... else { ... }
簡単な例:
// エラーを定義
enum CustomError : Error {
case ops
}
guard let a = retrieveAValue(),
let b = retrieveBValue() else {
throw CustomError.ops
}
まとめ
さすがswift
はまだ全然慣れてないので、今日はこれぐらいにします。ただswift
の魅力はなんとなくわかってきました。コンパイル言語でありながら使いやすい。kotlin
と似てるとは言えないが、kotlin
ともモダンな言語だなという所感です。
次はもうちょっとiOSを掘ってみます!