【Swift3】Alamofire4系を使ってRailsと連携する

swiftとrailsの連携記事を見ていたら気になったのでやってみた。

参考にした記事を書いてくれた方ありがとうございます。

cocoapodsインストール

以下の記事を参考にcocoapodsをインストールする。

qiita.com

//ホームディレクトリで実行
$gem install cocoapods

※cocoapodsはgemだけどbundlerで管理しているわけはない。一度インストールしたらMac自体にインストールされる

らしい。なるほどすごい。

iOSプロジェクトにset upする

まずは、iOSのプロジェクトを作成する。 xcodeを開いていつものようにiOSアプリを作成する。SingleViewです。

プロジェクトを作ったら、ターミナルで作ったディレクリに移動しよう。

$pod setup
$pod init

pod initしたら以下のようにプロジェクトにpodfileができる。 f:id:utr066:20170916225718j:plain ライブラリを入れるときにこのファイルをいじるみたい。

ライブラリを入れる

Podfileをいじる。今の中身はこんな感じ。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'swift_memo' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for swift_memo

  target 'swift_memoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'swift_memoUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

Pods for swift_memoの部分に入れたいライブラリを書けば入るっぽいね。

f:id:utr066:20170916230326j:plain pod “HogeHoge”

xcodeを落としてインストールする。

$pod install

f:id:utr066:20170916230517j:plain と、まあHogeHogeなんてねえよ!って言われますよね。 さっき書いたpod “HogeHoge"の記述を消して再度pod install。 f:id:utr066:20170916230804j:plain なんかこれは出る警告っぽいね。おk、次に行こう。

Alamofireのインストール

PodfileをいじってAlmofireをインストールする。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'swift_memo' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for swift_memo
    pod 'Alamofire', '~> 3.0'
  target 'swift_memoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'swift_memoUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

pod ‘Alamofire’, ‘~> 3.0'を追加したよ。

f:id:utr066:20170916232156j:plain Finderで見たときにこんな感じになって入ればokっぽい。

そして、プロジェクトをbuildすると以下のエラーが出て、buildできない。

ld: warning: directory not found for option '-F/Users/OhnoYutaro/Library/Developer/Xcode/DerivedData/swift_memo-ffumymlraemrulgesxlpgbkczuxp/Build/Products/Debug-iphonesimulator/Alamofire'
ld: framework not found Alamofire
clang: error: linker command failed with exit code 1 (use -v to see invocation)

調べて色々試したけど、だめだな。

もう一回projectを作ってやってみる。再度作ったprojectで以下を実行。

$pod setup
$pod init
//cocoapodsをインストールする記述後
$pod install

再度やってもダメだな。 そもそも、新しくできた.xcworkspaceの方を使うらしいね。 それを使ってbuildしたら、やばいほどエラー出たわ。 f:id:utr066:20170917001824j:plain 圧倒的エラー。なんか文法っぽいからバージョンかもしれんね。

Podfileを編集する

  # Pods for swift_memo
    pod 'Alamofire',
      :git => 'https://github.com/Alamofire/Alamofire.git',
      :branch => 'swift3'

swift3だからswift3を使用する指定っぽいのをする。 これもだめじゃん! f:id:utr066:20170917002651j:plain

公式みよ。

github.com

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target '<Your Target Name>' do
    pod 'Alamofire', '~> 4.5'
end
$pod install

f:id:utr066:20170917091613j:plain

できたプロジェクトをクリックして、xcodeを起動。 buildしたらうまくいきました。

公式の通りに~>, 4.5指定したらうまくいきましたね。 公式は正義。

swiftをいじる

メモアプリっぽいものを作る。 参考記事は以下です。ありがとうございます!

【iOS】SwiftでRailsと連携する方法 - Qiita

f:id:utr066:20170917175700j:plain 配置!

class WriteViewController: UINavigationController {

    
    @IBOutlet weak var textView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func tapSaveBtn(_ sender: Any) {
        let memo = Memo()
        memo.text = textView.text
        
        StockMemos.postMemo(memo: memo)
    }

}

textViewはoutlet接続。保存ボタンはアクション接続で保存ボタンをタップしたら、StockMemosメモのpostMemoが動くようにする。

StockMemos.swift

class StockMemos: NSObject {
    
    // 保存ボタンが押されたときに呼ばれるメソッドを定義
    class func postMemo(memo: Memo) {
        
        var params: [String: AnyObject] = [
            "text": memo.text as AnyObject
        ]
        
        // HTTP通信
        Alamofire.request(.POST, "http://localhost:3000/api/memos", parameters: params, encoding: .URL).responseJSON { (request, response, JSON, error) in
            
            println("=============request=============")
            println(request)
            println("=============response============")
            println(response)
            println("=============JSON================")
            println(JSON)
            println("=============error===============")
            println(error)
            println("=================================")
        }
        
    }

うまくいかない❤️

上記のコードはレスポンスを受け取って表示するような処理をしているみたいだから、値を送るだけにする。

        let parameters: Parameters = [
            "foo": [1,2,3],
            "bar": [
                "baz": "qux"
            ]
        ]
Alamofire.request("http://localhost:3000/api/memos", method: .post, parameters: parameters)

そして、もう一個。 xcodeのターミナルみたいな部分(なんて言うんだろう)を見てみると、以下のように出ている。

Temporary exceptions can be configured via your app's Info.plist file.

どうやらhttps通信が推奨でhttp通信は推奨されていないよう。これを解消するために、info.plistをいじる。

f:id:utr066:20170917173852j:plain

App Transport Security Settings(型はDirectory)を追加して、その中にAllow Arbitrary Loadsを入れる。ValueをYesにすることを忘れずに。

これで再度、適当に文字を入力して保存ボタンをタップ。

f:id:utr066:20170917174122j:plain

rails側にbinding.pryしていたので、見てみる。

f:id:utr066:20170917174209j:plain

おおー、ちゃんとrails側まで通信しているみたいですね。素晴らしい。 変な値を送っていたので、今回は入力した値をちゃんと送るようにする。

 let params: [String: AnyObject] = [
            "text": memo.text as AnyObject
        ]
        
        // Both calls are equivalent
        Alamofire.request("http://localhost:3000/api/memos", method: .post, parameters: params)

これで入力した値が送られるはず。

f:id:utr066:20170917174700j:plain

Testと入力して保存をタップ!

f:id:utr066:20170917174712j:plain

データベースを見にいくと、ちゃんと保存されていました。

というより、エラー処理の内容swiftの方で出さないなら、もはやこれだけでいいね。

//rails側
  def create
    Memo.create(create_params)
  end

  private
  def create_params
    params.permit(:text)
  end
//swift側
import UIKit
import Alamofire

class StockMemos: NSObject {
    

    class func postMemo(memo: Memo) {
        
        let params: [String: AnyObject] = [
            "text": memo.text as AnyObject
        ]
        
        // Both calls are equivalent
        Alamofire.request("http://localhost:3000/api/memos", method: .post, parameters: params)
        
        
    }
}

どんな感じでswiftとrailsを連携するのかわかってよかった。