rails

RailsのWebアプリとSwiftのiOSアプリを連携させてみた


 

どうもささおです!

今回はRailsのWebアプリとSwiftのiOSアプリを連携させてみます。注:そこそこ雑です

 

長いです。なんとまぁ全3回

1,RailsのWebアプリとSwiftのiOSアプリを連携させてみた  この記事

2,Webアプリ(API)へPOSTしてみる!

3,シンプル!APIKitで画像投稿してみよう!

 

 

 

いわゆWebアプリをAPIとして利用して、iOSでWebの情報を引っ張りますよ。

注:超シンプルで超初心者向けです・・・

RailsでWebAPIを作成する

まずは新しいプロジェクトを作成してください。

$ rails new my_web_app

$ cd my_web_app

 

次に

scaffoldで横着してしまいますが、Noteモデルに関する適当な機能を作成していきます。

$ rails g scaffold Note title:string content:text

 

あとはmigrationですね

$ rails db:migrate

 

あとは最後にnotes_controllerに一行だけ足していきます。

class NotesController < ApplicationController
  before_action :set_note, only: [:show, :edit, :update, :destroy]
  protect_from_forgery :except => [:index]
  # GET /notes
  # GET /notes.json
  def index
    @notes = Note.all
  end

  # GET /notes/1
  # GET /notes/1.json
  def show
  end

  # GET /notes/new
  def new
    @note = Note.new
  end
.
.
.
.
.

protect_from_forgery :except => [:index]

足したのはこの一行です。

今回はnotesのindexアクションを叩くことにしたので、

indexアクションにCSRF対策をしています。これが無いと動きません。

railsは一旦ここまです。

 

iOSアプリを作成する

iOSアプリはhttpクライアントにAPIKitを使用します。

jsonデコーダーにHikotokiを使用します。

「APIKit?Himotoki?なにそれ??」という方はこちらをご覧ください!

Swift3: APIKitの超簡単な使用方法

Swift3: APIKitとHimotokiの基本のき!

それでは進めていきます。

 

新しくiOSプロジェクトを作成してください。

作成が完了したらAPIKitとHimotokiをcocoapodsでインストールします。

「cocoapodsってなにそれ?」という方はこちらをご覧ください。

swift3:『Cocoapods』の導入方法!

 

ViewController.swiftの編集1

インストールが完了したら、

Main.storyboardにUITableViewを配置してIBOutlet接続をしてください。

今回はUITableViewにwebで作成したnotesを引っ張ってきて表示します。


import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }


}

 

次にTableViewのcellとDataSourceの設定を進めます。

TableViewついてわからない方はこちらをご覧ください。

swift3:初心者向け!UITableViewの使い方:delegate・datasourceについて

 

cellとDataSourceの設定をしたViewController.swiftがこちらです。
今のままではエラーが出ますが気にしないでください。

import UIKit

class ViewController: UIViewController, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!
    
    var notesArray = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return notesArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        return cell
    }
    
    


}

 

Noteモデルの作成

シンプルにこうなりました。

import Foundation
import Himotoki

struct Note: Decodable {
    let title: String
    let content: String
    
    static func decode(_ e: Extractor) throws -> Note {
        return try Note(title: e <| "title", content: e <| "content")
    }
}

structで作成したモデルにHimotokiのDecodableプロトコルを準拠させているところがミソです。

Decodableプロトコルのdecode関数でデコードしながらNoteを初期化しています。

Request作成

Request.swiftというファイルを作成してください。

import Foundation
import APIKit
import Himotoki

protocol WebRequest: Request {
    
}

extension WebRequest {
    var baseURL: URL {
        return URL(string: "http://localhost:3000")!
    }
}

extension WebRequest where Response: Decodable {
    
}

struct FetchNoteRequest: WebRequest {
    
    var path: String {
        return "/notes"
    }
    typealias Response = [Note]
    
    var method: HTTPMethod {
        return .get
    }
    
    func response(from object: Any, urlResponse: HTTPURLResponse) throws -> FetchNoteRequest.Response {
        return try decodeArray(object)
    }
}

このようになりました!

 

$ rails s

でターミナルで立てたローカルサーバーがAPIになるので叩くAPIのベースは「localhost:3000」です。
今回叩くAPIは、

URLは「localhost:3000/notes」

methodはGETです。

大切なのは

func response(from object: Any, urlResponse: HTTPURLResponse) throws -> FetchNoteRequest.Response { return try decodeArray(object) }

ここですね。

特にreturn try decodeArray(object)がキモです。

notesのindexアクションを叩くため、noteの配列をjsonで受け取ります。

なのでdecodeArray(object)を使ってデコードします。

 

ViewController.swiftを編集2

import UIKit
import APIKit

class ViewController: UIViewController, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!
    
    var notesArray: [Note] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self

        Session.send(FetchNoteRequest()) { result in
            switch result {
            case .success(let notes):
                self.notesArray = notes
                self.tableView.reloadData()
            case .failure(let err):
                print(err)
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return notesArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let note = notesArray[indexPath.row]
        cell.textLabel?.text = "title: \(note.title)  content: \(note.content)"
        return cell
    }

そこそこ変更を加えましたが、解説が必要なのは、

Session.send(FetchNoteRequest()) { result in
ここですね!

Session.sendの引数に作成したRequestを入れて通信を始めます。

resultがsuccessなのかfailureなのかで処理を変えています。

 

これで完成です!

しっかりとWebAPIの方で引っ張ってくるデータを作成してから起動して確認してみてください。

 

出来ない場合

残念ながら、このまま成功しない可能性があります。

できない場合baseURLをlocalhostではなくPCのIPアドレスを指定する必要があるかもしれません。

$ ifconfig | grep 192

のコマンドを打つと◯◯◯.◯◯◯.◯◯◯.◯◯◯ (◯には数字が入る)の12桁の数字が表示されるので、
Request.swiftのbaseURLにhttp://◯◯◯.◯◯◯.◯◯◯.◯◯◯ :3000に置き換えてください。

 

 


ABOUT ME
ささお
3年目iOSエンジニア。 スタートアップで働いておりやす。 プログラミングスクールとエンジニアのキャリアを考えたい。 作ったアプリ - https://apps.apple.com/us/app/loverprofile/id1463563845?l=ja&ls=1