Jun 102014
 

SwiftとObjective-Cの組み合わせ方のまとめ。何が出来て何が出来ないのか。特徴、型、互換性。

SwiftとObjective-Cの言語を利用する側として知っておく事のざっくりまとめ。SwiftからObjective-Cを使う場合、Objective-CからSwiftを使う場合。

Swiftとは?

  • CocoaやObjective-Cと互換性がある
  • SwiftからObjective-CのAPIを呼べる(systemフレームワーク)
  • SwiftからCライブラリを呼べる
  • SwiftからC++を直接呼べない
  • Objective-CからSwiftのAPIを呼べる
  • 拡張子は.swift
  • ヘッダーファイルがない(class記述に全ての情報を含むイメージ)

SwiftとObjective-C互換性

アプリ開発において利点…この互換性が最もフォーカスされるべき箇所。

  • Objective-CのコードからSwiftのクラスを呼べ、SwiftのコードからCocoaのクラスやパターン、書き方ができる
  • アプリ内にSwiftとObjective-Cの言語ファイルが混在していても大丈夫
  • 最新のSwift言語の機能を使うために、Objective-Cで開発したアプリの一部だけでもObjective-Cのコード箇所をSwiftのコードに置き換えることもできる

SwiftからObjective-Cを使う場合

Objective-CフレームワークやCライブラリ(UIKit/Foundation/SpriteKitなど)をimport文でインポート出来、Swiftのコードからモジュール(Module)としてAPI(メソッド/プロパティ/カテゴリ)を利用できる

例えば…

  • idはAnyObjectになる
  • NSStringはStringになる
  • pointerはoptional扱い

初期化プロセス

  • Swiftにはallocは存在しない
  • Swiftにはinitは存在しない
  • Swiftは型はお任せで大丈夫(明示的に指定出来るけれども)

initWith型はinitWith以降を小文字にして第一引数のラベルにするルール

[[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped]

initWithを消し、Frameをframeにして引数のラベルとして

UITableView(frame: CGRectZero, style: .Grouped)

型は省略できるが明示的に付けることもできる

let table = UITableView(frame: CGRectZero, style: .Grouped)
let table:UITableView = UITableView(frame: CGRectZero, style: .Grouped)

initWithを消し、Frameをframeにして引数のラベルとして

UITableView(frame: CGRectZero, style: .Grouped)

Objective-CのFactory型のメソッドは見やすく便利

[UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0]
UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)

プロパティアクセス

  • ドット構文
  • 括弧は不要
  • Objective-Cではgetterとプロパティは同じ構文だが、Swiftでは全く別物(Objective-C側で@propertyで定義したプロパティのみ、Swiftでプロパティとして扱う)

Objective-Cではプロパティのgetterのように扱っていたものも

[UIColor darkGrayColor]

以下とはならないケースもある、つまりはObjective-Cフレームワーク側で実際は

UIColor.darkGrayColor

@propertyを使わず、単にメソッドとして定義されている場合もあるものはSwiftでは明示的にメソッドとして使い分けてコードを書く。

UIColor.darkGrayColor()

メソッド呼び出し

  • ドット構文
  •  セレクタの最初の箇所がメソッド名
  • 最初の引数を括弧のすぐ内側に記述(引数の名前は不要)
  • それ以降は引数の名前が必要
  • 引数がない場合も括弧は必要

 

[myTableView insertSubview:mySubview atIndex:2];

第一引数は引数の名前は不要、それ以降は必要になる

myTableView.insertSubview(mySubview, atIndex: 2)

 AnyObject(Swift)とid(Objective-C)

  • Swift言語のAnyObjectは様々なオブジェクトを表す型
  • Objective-Cのidと同じ
  • Swiftへインポート(import)する際、id型はAnyObject型にマッピングされる
  • 定数/変数にいずれもどんなクラスのオブジェクトも割当可能
  • 割当時にキャストは不要
  • ただし、オブジェクトに存在しないメソッドを呼ぶと実行時にエラー(実行するまでAnyObjectが何の型か特定されないので安全でないコードになるので注意)
  • エラーを出さないためにSwiftにはいくつかオプションがある

AnyObject型は様々なオブジェクトを受け入れられる

var cell: UITableViewCell = UITableViewCell()
var myObject: AnyObject = UITableViewCell()

キャスト不要

NSDate(myObject).dateByAddingTimeInterval(10)//Swiftでは不要
myObject.dateByAddingTimeInterval(10)

そもそも存在しない場合は実行した時点でエラー発生する可能性あり

myObject.start()

オプション(optinals)

Objective-Cエラーを抑えるSwiftの機能がある

1)?でエラーを回避できる(存在しないメンバーを呼んでる例)

var myObject = NSDate()
let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)

2)if-let構文でメソッド応答の有無の確認ができる

if let fifthCharacter = myObject.characterAtIndex(5) {
    println("Found \(fifthCharacter) at index 5")
}

ダウンキャスト(AnyObjectから特定のオブジェクト型へ)

  • キャスト成功する保証はない
  • オプションを戻す可能性がある(nilのようなもの)
  • その値を確認できる

ユーザ設定のロードで日付を取り出す過程…NSDate型か格納されているかは不明

let userDefaults = NSUserDefaults.standardUserDefaults()
let lastRefreshDate: AnyObject? = userDefaults.objectForKey("LastRefreshDate")

キャスト成功か値を確認

if let date = lastRefreshDate as? NSDate {
    println("\(date.timeIntervalSinceReferenceDate)")
}

nilじゃないのが確実ならそのまま呼んでも大丈夫

let myDate = lastRefreshDate as NSDate

nilの扱い

  • Swiftでは、全ての値はnilではない
  • ただし、Swiftでは値がない事を示すためにnilを使える
  • 一方、Objective-Cの世界ではnilだったりnilでなかったりする
  • Objective-Cのオブジェクトを利用する前に、nilチェックをすることが確実(値が確実に空じゃないといえる場合を除く)

Extension

  • Objective-Cのcategoryに近い
  • 既存クラス(class)や構造体、列挙体の振る舞いを拡張する
  • カスタム型の拡張が出来る
  • システムフレームワークの拡張が出来る
  • プロパティを追加できる(算術のみ/書換は無理)
  • protocol追加に利用できる
  • Objective-C型のメソッドやプロパティはoverrideできない

拡張方法

  1. モジュールをimportで読み込む
  2. 同じ名前のクラスや構造体、列挙体を参照する
  3. 追加する中身を記述

 

extension CGRect {
    var area: CGFloat {
    return width * height
    }
}

クロージャ(Closures)

  • Objective-CのblockとSwiftではクロージャは互換性がある
  • クロージャと関数は同じ型
  • Objective-Cの__blockがSwiftでは標準的な値の扱われ方となる
void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {/* ... */}
let completionBlock: (NSData, NSError) -> Void = {data, error in /* ... */}

Swiftでのオブジェクト比較

  • ==を使う(オブジェクトの中身の比較)
  • ===を使う(定数/変数が同じインスタンスを参照しているか)

 

 

Objective-CからSwiftを使う場合

SwiftからObjective-Cへのインポートも似たようなイメージ(Swiftで書いたAPIがObjective-Cヘッダとして生成されSwiftモジュールとして利用可能になる)

  • StringはNSStringになるなど上記とは逆方向マッピング
  • 一部はマッピングできないので注意(つまり新言語Swiftのみの進化した言語機能、特徴的な部分は旧言語Objective-Cとは互換がとれないところもある)

 

 Swift言語の型互換性

Objective-Cから派生したSwiftのクラスは自動的に互換性が保たれる(@objcが自動挿入される)が、 Objective-Cから派生してないSwiftのクラスをObjective-Cのコードで利用する場合、@objcを使う必要がある。@objcによりObjective-Cの実行環境でSwiftのAPIが利用できるようになる。

  • Objective-Cから利用したいメソッド、プロパティ、クラスの前に@objc
  • メソッドのシグネチャーが翻訳される(Swift->Obj-Cのケースの逆)
  • @objcをObjective-Cで参照される時の別名定義のために使えるSwiftで書かれたクラス側とクラス名を一致させる時に@objcを使う(Objetive-Cでアーカイブオブジェクト(Archived Objects)を扱っている場合オブジェクト内にクラス名が保存されるため)
@objc(Squirrel)
class りす {
    @objc(initWithName:)
    init (名前: String) { /*...*/ }
    @objc(hideNuts:)
    func 隠す(Int) { /*...*/ }
}

Objective-Cセレクタ

  • Objective-Cのセレクタはメソッド名を参照する型である。
  • SwiftではObjective-Cから派生したクラスの場合、クラス内のメソッドやプロパティはObjective-Cのセレクタとして利用できる
  • SwiftではObjective-Cから派生していないクラスの場合、@objをつける事でセレクタとして利用できる
  • performSelector:メソッドはSwiftには導入されていない

Objective-Cのクラスから派生しているメンバ

import UIKit
class MyViewController: UIViewController {

    func tappedButton(sender: UIButton!) {
        println("tapped button")
    }
}

これはSelector型と同じ。

let mySelector: Selector = "tappedButton:"

 


Optionals

オプション(optional)型は「値が存在しない」ことを表す。Objective-Cにおけるポインタのnilに近い概念だが、クラスではなくすべての型に動作するもの。オプションはObjective-Cのポインタより安全かつ様々な表現を持つ。Swiftの最大の特徴である機能の心臓部に位置する概念。

 

コメント

個のコメント

Powered by Facebook Comments

 Posted by at 16:52

  2 Responses to “Objective-CとSwiftの組み合わせ方のまとめ”

  1. […] クラスを記述すること。 前回はSwiftとObjective-Cの互換性やそれぞれから機能をどのように利用するか相互運用について概要を書いたので、パート2は掘り下げて記述する。 […]

  2. Objective-CとSwiftの組み合わせ方のまとめ – http://t.co/H3O5rKOOws

Sorry, the comment form is closed at this time.