開発メモ

開発関係のメモをいろいろと。たぶん。

Using Swift with Cocoa and Objective-Cのメモ(その1)

はじめに

これは、『Using Swift with Cocoa and Objective-C』を読んだ時の個人的なメモです。なので、引用はすべて『Using Swift with Cocoa and Objective-C』から。

iTunes - ブック - Apple Inc.「Using Swift with Cocoa and Objective-C
https://itunes.apple.com/jp/book/using-swift-cocoa-objective/id888894773?mt=11


Getting Started

Basic Setup

Understanding the Swift Import Process

  • Objective-CやCのモジュールをSwiftで直接取り込むことが出来るよ
    メモ: 逆に言うと、モジュールになってないものは取り込めない? 要確認

  • 具体的にはこんな感じになるよ

import Foundation
  • この作業で型はこんな感じになるよ

    • Objective-Cの型はSwiftで該当するものに置き換えられるよ。例えば、idだとAnyObjectになるよ
    • Objective-Cのコアになる型はSwiftで似たようなものに置き換えられるよ。例えば、NSStringはStringになるよ
    • Objective-Cのコンセプトも置き換えられるよ。例えばポインターはオプション変数になるよ
  • NOTE: C++のコードを直接取り込むことは出来ないよ

Interoperability

Interacting with Objective-C APIs

  • SwiftとObjective-Cには相互運用性があるよ
  • つまり、片方の言語で書いたコードを、もう一つの言語から使うことが出来るよ

Initialization

  • Objective-Cのinit関係のメソッドは、Swiftだとイニシャライザーになるよ

  • 最初の『init』は省略されて、残りがイニシャライザーの引数になるよ

  • 『initWith』ではじまってる場合は、そこまで省略されるよ
  • 残ったキーワードの最初の文字は小文字になるよ
  • 残りのセレクターは、そのまま引数になるよ

メモ: 説明を読むよりコードを見たほうがわかりやすい

UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
  • Swiftだとこう
let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)
  • Objective-Cのファクトリーメソッドは、Swiftの便利イニシャライザーになるよ

  • Objective-Cだとこう

UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];
  • Swiftだとこう
let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)

Accessing Properties

  • Objective-Cだと引数なしで戻り値が1つのメソッドをプロパティの取得と同じように使えたけど、Swiftだとこれは出来ないよ
  • SwiftからObjective-Cのクラスを使う場合、@propertyのついたプロパティだけがプロパティとして使えるよ

Working with Methods

  • Objective-CのメソッドをSwiftから使う場合、セレクターがメソッドの名前と引数名になるよ
  • Objective-Cセレクターの最初の部分がメソッドの名前になるよ
  • セレクターの最初の引数は、Swiftのメソッドの最初の引数になって、これは名前無しだよ
  • セレクターの残りの引数は、メソッドの名前付き引数になるよ

メモ: これも、説明を読むよりコードを見たほうがわかりやすい

[myTableView insertSubview:mySubview atIndex:2];
  • Swiftだとこう
myTableView.insertSubview(mySubview, atIndex: 2)

id Compatibility

  • Objective-CのidはSwiftだとAnyObjectプロトコルになるよ

  • AnyObjectを使う場合、@objc属性の付いたメソッドやプロパティなら、キャスト無しで呼び出すことが出来るよ

  • もちろん、存在しないメソッドやプロパティを使うとランタイムエラーになるよ
  • オプション変数やオプション連鎖を使えば、メソッドやプロパティを使うのが安全になるよ

Working with nil

  • Objective-Cのオブジェクトはnilになる可能性があるから、Swiftに取り込むとオプション変数になるよ
  • Objective-Cのメソッドやプロパティで得られる値が、絶対にnilにならないってわかってる場合、implicitly unwrapped optionalsを使うことも出来るよ

Extensions

  • エクステンションはObjective-Cから取り込んだものにも使えるよ
  • エクステンションで、既存のメソッドやプロパティをオーバーライドすることは出来ないよ

Closures

void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {/* ... */}
  • Swiftだとこう
let completionBlock: (NSData, NSError) -> Void = {data, error in /* ... */}
  • SwiftのクロージャObjective-Cのブロックは互換性があるよ
  • だから、ブロックを必要とするObjective-Cのメソッドに、Swiftのクロージャを渡すことが出来るよ
  • Swiftの関数はクロージャと同じものだから、関数を渡すことも出来るよ
  • クロージャはブロックと同じように周りの変数をキャプチャするけど、変数が変更可能だよ
  • つまり、Objective-Cで『__block』を指定してたのと同じ動きがデフォルトになってるよ

Object Comparison

  • Swiftでは、NSObjectから派生したクラスを『==』で比較できるよ
    これは、標準の実装では『isEqual:』を呼び出すだけだよ。

  • 自作クラスを比較できるようにする場合、ハッシュ関係の機能も実装するべきだよ

Swift Type Compatibility

  • SwiftでNSObjectから派生したクラスを作った場合、そのままで、Objective-Cでも使えるよ
  • そうじゃない場合、@objc属性を付ける必要があるよ
  • @IBOutletや@IBActionや@NSManaged属性を付けると、自動的に@objc属性も付くよ

  • Swiftで作ったAPIObjective-Cでもそのまま使えるよ

  • ただし、イニシャライザーは名前が変わってくるから注意が必要だよ

  • 『@objc(name)』の形で、Objective-Cで使う時の名前を指定することも出来るよ
    これは、Objective-Cアーカイブ可能なクラスをSwiftに移行するときに便利だったりするよ。

Objective-C Selectors

  • Objective-Cセレクターは、Objective-Cのメソッドを参照するためのものだよ
  • これは、SwiftだとSelector構造体になるよ
  • Selector構造体は文字列から生成できるよ
let mySelector: Selector = "tappedButton:"
  • セレクターを受け取るメソッドに文字列を渡すと、自動的にSelector構造体に変換されるよ
    メモ: 暗黙の型変換が起きる? 要確認

  • Swiftには『performSelector:』は無いよ

Writing Swift Classes with Objective-C Behavior

Adopting Protocols

id<UITableViewDelegate> delegate;
  • Swiftだとこう
UITableViewDelegate delegate

Working with Outlets and Actions

  • Swiftだと、アウトレットやアクションは『@IBOutlet』や『@IBAction』で指定するよ
  • アウトレットコレクションも『@IBOutlet』だよ
  • アウトレットは、自動でweakになってnilで初期化されるよ

Live Rendering

  • 『@IBDesignable』と『@IBInspectable』は、Interface Builderでカスタムビューをデザインするときに使えるよ

  • UIViewかNSViewから派生したクラスでクラス名に@IBDesignable属性を付けると、カスタムビューをInterface Builderに追加できるよ

  • 同じように@IBInspectable属性をプロパティに付けると、Interface Builderからプロパティを編集できるようになるよ

Copy Semantics

  • Objective-Cのプロパティでcopyを指定したものは、Swiftだと@NSCopying属性になるよ

Implementing Core Data Managed Object Subclasses

  • NSManagedObjectを派生したクラスでCore Dataと連携するプロパティには、@NSManaged属性を付けるよ

Working with Cocoa Data Types

  • Swiftは自動的に、SwiftとObjective-Cの型を変換するよ

メモ: 要確認

Strings

  • 文字列はStringとNSStringで橋渡しできるよ
  • Stringが必要な時はNSStringをキャストすれば変換できるよ

Localization

  • Objective-Cだと、ローカライズにNSLocalizedString関係のマクロを使ってたよ
  • Swiftだと、『NSLocalizedString(key:tableName:bundle:value:comment:)』を使うよ
    この関数は、デフォルト値をいろいろ持ってるから、マクロの置き換えに使えるよ。

メモ: 要確認

Numbers

  • Swiftは自動的にIntやFloatとかをNSNumberに橋渡しするよ
  • このおかげで、NSNumberを引数に取る所にIntやFloatを直接書けるよ

  • NSNumberに自動で橋渡し出来るのは以下の型だよ

    • Int
    • UInt
    • Float
    • Double
    • Bool

Foundation Data Types

  • SwiftはNSUIntegerもNSIntegerもIntにするよ

Foundation Functions

  • Objective-CだとNSLogをロギングに使うよ
  • Swiftだとprintやprintlnを使うよ
  • NSAssertはassertになるよ

メモ: いろいろ、要確認

Core Foundation

  • Core Foundationの型はSwiftだとクラスになるよ
  • メモリ管理の註釈がちゃんとしてれば、自動的にオブジェクトの管理もやってくれるよ

Remapped Types

  • SwiftだとCore Foundationの名前が置き換えられるよ
    名前の後ろの『Ref』が切り落とされるよ。

メモ: 要確認

Memory Managed Objects

  • 注釈付きのAPIから取得したCore Foundationのオブジェクトは、自動的に管理されるよ
    つまり、CFRetainやCFReleaseやCFAutoreleaseを自分で呼ぶ必要はないよ。

  • 自分で作ったCの関数やObjective-CのメソッドからCore Foundationのオブジェクトを返す時は、『CF_RETURNS_RETAINED』か『CF_RETURNS_NOT_RETAINED』の註釈を使うよ

Unmanaged Objects

  • 註釈のついてないAPIからCore Foundationのオブジェクトを返されると、自動で管理できないよ
  • この場合、SwiftはCore Foundationのオブジェクトを『Unmanaged<T>』構造体で管理するよ

  • Objective-Cだとこう

CFStringRef StringByAddingTwoStrings(CFStringRef string1, CFStringRef string2)
  • Swiftだとこうなる
func StringByAddingTwoStrings(CFString!, CFString!) -> Unmanaged<CFString>!
  • Unmanagedで受け取ったオブジェクトは、使う前にManagedオブジェクトに変換しないと駄目だよ
  • このために、Unmanaged構造体は2つのメソッドが用意してあるよ
    『takeUnretainedValue()』と『takeRetainedValue()』だよ。

  • 例えば、オブジェクトを管理しない関数を呼ぶ場合、こんな感じになるよ

let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
// memoryManagedResult is a memory managed CFString
  • いちおう、retain()やrelease()やautorelease()を呼ぶこともできるけど、このやり方はおすすめできないよ

とりあえず、ここまで。 (2014/06/18)