Contenu connexe Similaire à ゲンバのSwift (20) Plus de Yuichi Adachi (12) ゲンバのSwift2. 安達 勇一
• 2013/12 入社
• TwitterID:
@UsrNameu1
• Github:
https://github.com/UsrNameu1
• Blog:
http://dev.classmethod.jp/
author/yad
• で連載やって
ます
5. UIKitでのイベントハンドリング
• UIControl, UIBarButtonItem の target, action
navigationItem.leftBarButtonItem =
UIBarButtonItem(title: NSLocalizedString("cancel", comment: ""),
style: .Bordered,
target: self,
action: Selector(“cancelButtonDidTapped:”));
6. UIKitでのイベントハンドリング
• UIControl, UIBarButtonItem の target, action
navigationItem.leftBarButtonItem =
UIBarButtonItem(title: NSLocalizedString("cancel", comment: ""),
style: .Bordered,
target: self,
action: Selector(“cancelButtonDidTapped:”));
7. UIKitでのイベントハンドリング
• UIControl, UIBarButtonItem の target, action
navigationItem.leftBarButtonItem =
UIBarButtonItem(title: NSLocalizedString("cancel", comment: ""),
style: .Bordered,
target: self,
action: Selector(“cancelButtonDidTapped:”));
UIKitのAPIのイベントハンドリングでは
Selectorが要を握る
13. Objective-Cとの比較
• Objective-C
• Swift
[removeButton addTarget:self
action:@selector(removeButtonDidTouchUpInside:)
forControlEvents:UIControlEventTouchUpInside];
removeButton.addTarget(self,
action: Selector("removeButtonDidTouchUpInside:"),
forControlEvents: .TouchUpInside)
14. Objective-Cとの比較
• Objective-C
• Swift
[removeButton addTarget:self
action:@selector(removeButtonDidTouchUpInside:)
forControlEvents:UIControlEventTouchUpInside];
removeButton.addTarget(self,
action: Selector("removeButtonDidTouchUpInside:"),
forControlEvents: .TouchUpInside)
⇧Selector名が間違っていたら
コンパイラが警告を出してくれる
15. Objective-Cとの比較
• Objective-C
• Swift
[removeButton addTarget:self
action:@selector(removeButtonDidTouchUpInside:)
forControlEvents:UIControlEventTouchUpInside];
removeButton.addTarget(self,
action: Selector("removeButtonDidTouchUpInside:"),
forControlEvents: .TouchUpInside)
⇧Selector名が間違っていたら
コンパイラが警告を出してくれる
⇧Selector名が間違っていても
コンパイラは警告を出してくれない
16. Objective-Cとの比較
• Objective-C
• Swift
[removeButton addTarget:self
action:@selector(removeButtonDidTouchUpInside:)
forControlEvents:UIControlEventTouchUpInside];
removeButton.addTarget(self,
action: Selector("removeButtonDidTouchUpInside:"),
forControlEvents: .TouchUpInside)
⇧Selector名が間違っていたら
コンパイラが警告を出してくれる
⇧Selector名が間違っていても
コンパイラは警告を出してくれない
19. BlocksKit
• Before
• After
removeButton.addTarget(self,
action: Selector("removeButtonDidTouchUpInside:"),
forControlEvents: .TouchUpInside)
⇧Selector名が間違っていても
コンパイラは警告を出してくれない
removeButton.bk_addEventHandler({[weak self] sender in
self?.removeButtonDidTouchUpInside(sender)
return Void()
}, forControlEvents: .TouchUpInside)
⇧ハンドラの中でメソッドを直に呼び出すため、
メソッド名が間違っていたらコンパイラはエラーになる
25. 2つのFramework : Quick, Nimble
• QuickはテストのためのBDD流DSLを用意
• Nimbleは実際の値と期待する値を比較するマッチャー
• テストはプロダクトコードに含まれない為、
iOS 8 向けにインストール
26. 2つのFramework : Quick, Nimble
• 病院にかかわる一連のモデル
create
confirm
use
public struct Diagnosis {
public let name: String
public init(name: String) {
self.name = name
}
}
public protocol Examinable {
func examine() -> Diagnosis
}
public class Doctor: Examinable {
public init() {}
public func examine() -> Diagnosis {
return Diagnosis(name: "cold")
}
}
public class Hospital {
private let examinable: Examinable
public init(examinable: Examinable) {
self.examinable = examinable
}
public func serve() -> Diagnosis {
return examinable.examine()
}
}
28. 2つのFramework : Quick, Nimble
• 診断データ型
public struct Diagnosis {
public let name: String
public init(name: String) {
self.name = name
}
}
30. 2つのFramework : Quick, Nimble
• 医者クラス
public class Doctor: Examinable {
public init() {}
public func examine() -> Diagnosis {
return Diagnosis(name: "cold")
}
}
31. 2つのFramework : Quick, Nimble
• 病院クラス
public class Hospital {
private let examinable: Examinable
public init(examinable: Examinable) {
self.examinable = examinable
}
public func serve() -> Diagnosis {
return examinable.examine()
}
}
32. 2つのFramework : Quick, Nimble
• BDD Example
class HospitalSpecs: QuickSpec {
override func spec() {
describe("病院の診断について") {
context("診察できる人が診断を行うとき") {
let doctor = Doctor()
let hospital = Hospital(examinable: doctor)
it("診察できる人の診断を返すこと。") {
expect(hospital.serve().name) == "cold"
}
}
}
}
}
33. SwiftでのMock実装例
class HospitalSpecs: QuickSpec { // protocol準拠でMockを使う
override func spec() {
describe("病院の診断について") {
context("診察できる人が診断を行うとき") {
class MockExaminable: Examinable {
override func examine() -> Diagnosis {
return Diagnosis(name: "cold")
}
}
let mock = MockExaminable()
let hospital = Hospital(examinable: mock)
it("診察できる人の診断を返すこと。") {
expect(hospital.serve().name) == "cold"
}
}
}
}
}
34. SwiftでのMock実装例
class HospitalSpecs: QuickSpec { // protocol準拠でMockを使う
override func spec() {
describe("病院の診断について") {
context("診察できる人が診断を行うとき") {
class MockExaminable: Examinable {
override func examine() -> Diagnosis {
return Diagnosis(name: "cold")
}
}
let mock = MockExaminable()
let hospital = Hospital(examinable: mock)
it("診察できる人の診断を返すこと。") {
expect(hospital.serve().name) == "cold"
}
}
}
}
}
35. SwiftでのMock実装例
class HospitalSpecs: QuickSpec { // 継承でMockを使う
override func spec() {
describe("病院の診断について") {
context("診察できる人が診断を行うとき") {
class MockDoctor: Doctor {
override func examine() -> Diagnosis {
return Diagnosis(name: "headache")
}
} // HospitalがDoctorを直接用いている時も使える
let mock = MockDoctor()
let hospital = Hospital(examinable: mock)
it("診察できる人の診断を返すこと。") {
expect(hospital.serve().name) == "headache"
}
}
}
}
}
36. SwiftでのMock実装例
class HospitalSpecs: QuickSpec { // 継承でMockを使う
override func spec() {
describe("病院の診断について") {
context("診察できる人が診断を行うとき") {
class MockDoctor: Doctor {
override func examine() -> Diagnosis {
return Diagnosis(name: "headache")
}
} // HospitalがDoctorを直接用いている時も使える
let mock = MockDoctor()
let hospital = Hospital(examinable: mock)
it("診察できる人の診断を返すこと。") {
expect(hospital.serve().name) == "headache"
}
}
}
}
}
42. OSSのインストール
• git submodule でのOSS導入例(Alamofire)
$ cd (Project dir)
$ git submodule add https://github.com/
Alamofire/Alamofire.git
47. iOS7でOSSを使う
• iOS8 では Dynamic Library の形式では使えないので直
にソースファイルをプロジェクトに入れる必要がある
• 極力 git submodule の更新のみでファイル追従を行うた
めにCopyせずにソースファイルへの参照をリンク
50. 使用中のOSS
• Alamofire : HTTP通信のためのOSS
• SwiftyJSON : JSONハンドリングのためのOSS
• BrightFutures : 非同期処理のためのOSS
• Quick : テストのDSLを提供するOSS
• Nimble : テストのマッチャ−を提供するOSS
51. • Alamofire
• SwiftyJson
• BrightFutures
• Quick
• Nimble
テストターゲットのみに含まれる為、
テストをiOS8向けとして
Dynamic frameworkでプロジェクトに入れた
使用中のOSS
52. • Alamofire
• SwiftyJson
• BrightFutures
• Quick
• Nimble
テストターゲットのみに含まれる為、
テストをiOS8向けとして
Dynamic frameworkでプロジェクトに入れた
アプリターゲットの対象に
iOS7が含まれるため
frameworkとしてではなく、
ソースの参照を保持するようにした
使用中のOSS
66. NSManagedObject in Test
• NSManagedObjectサブクラスを用いたクラスのテスト
で実行時に落ちる
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'executeFetchRequest:error: A fetch request must have an entity.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010387ef35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000103517bb7 objc_exception_throw + 45
2 CoreData 0x00000001025e137d -[NSManagedObjectContext
executeFetchRequest:error:] + 4541
67. NSManagedObject in Test
• NSManagedObjectサブクラスを用いたクラスのテスト
で実行時に落ちる
• Objective-Cから見た時のNSObjectサブクラス名もSwift
のクラスに対してはModule名.クラス名
• @objc()キーワードを使ってObjective-Cから見た時の
NSObjectサブクラス名を変更する
69. NSManagedObject in Test
• Before
• After
class Product: NSManagedObject {
@NSManaged var name: String
}
@objc(Product)
class Product: NSManagedObject {
@NSManaged var name: String
}
70. NSManagedObject in Test
• Before
• After
class Product: NSManagedObject {
@NSManaged var name: String
}
@objc(Product)
class Product: NSManagedObject {
@NSManaged var name: String
}
@objc()キーワードを使ってObjective-Cから見た
時のNSObjectサブクラス名を変更
72. Storyboard & InterfaceBuilder
• Xcode 6 より追加されたModule入力欄にターゲットモ
ジュールを入力
• またはViewController宣言の前に
@objcでObjective-Cから見た
クラス名を記述
http://stackoverflow.com/questions/
24924966/xcode-6-strange-bug-
unknown-class-in-interface-builder-file
84. Chris Lattnerの哲学
• The Architecture of Open Source
Applications : Chapter 11 LLVM
• 邦語訳へのリンク
http://m-takagi.github.io/aosa-ja/