#はじめに
オイシックス・ラ・大地(以下オイラ大地)の新卒エンジニアの城間です。
この記事はオイラ大地株式会社アドベントカレンダーの19日目の記事になります。
Oisix ra daichi Inc. Advent Calendar 2018
11月からiosエンジニアとして所属しており、本記事では課題として作ったアプリを
書いていきたいと思います。
Swiftは初学者で色々とつまづいていたので、参考になれば幸いです。
#使用したAPI
connpass APIを使用しました。(https://connpass.com/about/api/)
レスポンスフィールドとしては下記を取得します。
フィールド | 型 | 説明 |
---|---|---|
events | 配列(複数要素) | 検索結果のイベントリスト |
title | 文字列(UTF-8) | タイトル |
event_url | 文字列(UTF-8) | connpass.com 上のURL |
#JSONの値を取得する
###Codable
レスポンスの取得にはCodableを使用しています。
SwiftyJSONなどのライブラリを使用してJSON形式のデータを構造体に変換するなどの処理をする方法もありますが、CodableはSwiftが提供しておりライブラリを使わずシンプルに記述できるので使いました。
CodableでconnpassAPIのデータを変換します。
struct Resultsfield: Codable {
var events: [Events]
struct Events: Codable {
var title: String
var event_url: String
}
}
###APIを叩く
connpassAPIを叩くためにURLSessionを使いました。
URLSessionとはリクエストを受けて通信を行うクラスです。
struct Connpass {
//非同期処理の後にクロージャを実行する
static func fetchEvent(completion: @escaping (Resultsfield) -> Swift.Void) {
let url = "https://connpass.com/api/v1/event/?keyword=python"
//URLComponentsはクエリストリングの追加などが可能
let urlComponents = URLComponents(string: url)
//非同期で通信を行う
let task = URLSession.shared.dataTask(with: (urlComponents?.url!)!) { data, response, error in
guard let jsonData = data else {
return
}
do {
//jsonのマッピング
let resultsfields = try JSONDecoder().decode(Resultsfield.self, from: jsonData)
completion(resultsfields)
} catch {
print(error.localizedDescription)
}
}
////task.resume()メソッドを実行すると通信が開始される
task.resume()
}
}
#tableViewにデータを表示させる
今回はextensionを使いクラスに定義を追加しました。
拡張先ではcellに取ってきた値を代入する処理をしています。
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
let resultsfield = resultsfields.events[indexPath.row]
cell.textLabel?.text = resultsfield.title
cell.detailTextLabel?.text = resultsfield.event_url
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultsfields.events.count
}
}
###SafariServices
遷移先webページをSafariビューっぽい感じにするために
SFSafariViewControllerを使用します。
SafariServicesをimportして下記のように記述します。
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let resultsfield = resultsfields.events[indexPath.row]
let webPage = resultsfield.event_url
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
present(safariVC, animated: true, completion: nil)
}
}
#ソースコード
全体としては下記のようになります。
import UIKit
import SafariServices
struct Resultsfield: Codable {
var events: [Events]
struct Events: Codable {
var title: String
var event_url: String
}
}
struct Connpass {
static func fetchEvent(completion: @escaping (Resultsfield) -> Swift.Void) {
let url = "https://connpass.com/api/v1/event/?keyword=python"
let urlComponents = URLComponents(string: url)
let task = URLSession.shared.dataTask(with: (urlComponents?.url!)!) { data, response, error in
guard let jsonData = data else {
return
}
do {
let resultsfields = try JSONDecoder().decode(Resultsfield.self, from: jsonData)
completion(resultsfields)
} catch {
print(error.localizedDescription)
}
}
task.resume()
}
}
class ViewController: UIViewController {
private var tableView = UITableView()
var resultsfields: Resultsfield = Resultsfield(events: [])
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.frame = view.frame
tableView.dataSource = self
view.addSubview(tableView)
Connpass.fetchEvent(completion: { (resultsfields) in
self.resultsfields = resultsfields
DispatchQueue.main.async {
self.tableView.reloadData()
}
})
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
let resultsfield = resultsfields.events[indexPath.row]
cell.textLabel?.text = resultsfield.title
cell.detailTextLabel?.text = resultsfield.event_url
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultsfields.events.count
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let resultsfield = resultsfields.events[indexPath.row]
let webPage = resultsfield.event_url
let safariVC = SFSafariViewController(url: NSURL(string: webPage)! as URL)
present(safariVC, animated: true, completion: nil)
}
}
#最後に
最初は基礎文法などをわかっておらずコピペ頼りな所もあったのですが
このメソッドはどういう意味をもっているという理解や自分で一から作り上げる事が
やっぱり一番の近道だなと作っていて感じました。
追加機能として検索機能やソート機能
RxSwiftに書き換えなどしているので、出来次第また記事をあげたいと思います!