swiftのアプリ開発でハマったこと

72
Swift LT @Wantedly 2014-07-17 yohei sugigami

Upload: youhei-sugigami

Post on 08-Sep-2014

25 views

Category:

Technology


0 download

DESCRIPTION

アジェンダ ・Swiftのアプリ開発でハマったこと 10個 ・Xcode6とSwiftのアプリ開発で踏んだ地雷たち8個 WantedlyではiOS, Android, Railsエンジニアを募集しています! 興味がある方はこちからご連絡ください [email protected] こちらからでもOKです 新しい技術にどんどん挑戦したいモバイルエンジニア・ウォンテッド!! https://www.wantedly.com/projects/7755

TRANSCRIPT

Page 1: Swiftのアプリ開発でハマったこと

Swift LT @Wantedly

2014-07-17 yohei sugigami

Page 2: Swiftのアプリ開発でハマったこと

杉上 洋平 (スギガミ ヨウヘイ) GitHub: @susieyy 先月JOINしたばかりの新米プログラマー !!!

Wantedlyでは高いQiita力が求められる :)

Swiftで2位

Page 3: Swiftのアプリ開発でハマったこと

・Swiftのアプリ開発でハマった

 こと 10個

!

・Xcode6とSwiftのアプリ開発で  踏んだ地雷たち8個

アジェンダ

Page 4: Swiftのアプリ開発でハマったこと

Xcode6で新規のアプリを開発した時に気づいたことをまとめます。アプリの仕様は以下のとおり。

!

- 開発言語はSwift

- Cocoapodsで既存Objcのライブラリを利用

- デプロイターゲットはiOS8以上

- Storyboardを利用

- AutolayoutとSizeClassesを利用

Page 5: Swiftのアプリ開発でハマったこと

開発環境は以下のとおり。

!

- Xcode6はBeta2, 3を利用

- 検証実機はiOS8 Beta2, 3をインストールのiPhone5

!

Beta2で開発していたら、Beta3が出ました \(^o^)/

Page 6: Swiftのアプリ開発でハマったこと

Swiftのアプリ開発でハマったこと

Page 7: Swiftのアプリ開発でハマったこと

以下の様なObjCメソッドにSwiftのクロージャを渡す方法

@interface HogeFuga : NSObject+ (void) hogeUsingBlock:(id)bock;@end

Page 8: Swiftのアプリ開発でハマったこと

ObjC id = Swift AnyObject

Page 9: Swiftのアプリ開発でハマったこと

HogeFuga.hogeUsingBlock( { () -> () in println("Fuga")})

ERROR Type '() -> ()' does not conform to protocol 'AnyObject'

Page 10: Swiftのアプリ開発でハマったこと

var closures: AnyObject = { () in println("Fuga")}

ERROR Type '() -> ()' does not conform to protocol 'AnyObject'

Page 11: Swiftのアプリ開発でハマったこと

typedef void (^Block)();!@interface HogeFuga (Wrapper)+ (void) hogeUsingBlockWrapper:(Block)block;@end!@implementation HogeFuga (Wrapper)+ (void) hogeUsingBlockWrapper:(Block)block;{ [HogeFuga hogeUsingBlock:block];}@end

ObjCで型を明示したブロックを 持つメソッドでラップする

Page 12: Swiftのアプリ開発でハマったこと

NSObject#descriptionをオーバーライドする

Page 13: Swiftのアプリ開発でハマったこと

class Hoge: NSObject { var name: String? var note: String? override func description() -> String { return "Name = \(self.name), Note = \(self.note)" }}

ERROR Method does not override any method from its superclass

Page 14: Swiftのアプリ開発でハマったこと

class Hoge: NSObject { var name: String? var note: String? override var description: String! { get { return "Name = \(self.name), Note = \(self.note)" } }}

プロパティのオーバーライドする

Page 15: Swiftのアプリ開発でハマったこと

ObjCのenum値をSwift記法で記載する方法がわからない

Page 16: Swiftのアプリ開発でハマったこと

SwiftUIViewAutoresizing.FlexibleLeftMargin

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, …}

ObjCUIViewAutoresizingFlexibleLeftMargin

わかりやすい例

Page 17: Swiftのアプリ開発でハマったこと

SwiftUIViewAnimationOptions.LayoutSubviews

typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) { UIViewAnimationOptionLayoutSubviews = 1 << 0, UIViewAnimationOptionAllowUserInteraction = 1 << 1, …}

ObjCUIViewAnimationOptionLayoutSubviews

許容範囲な例

Page 18: Swiftのアプリ開発でハマったこと

SwiftHogeStyle.FugaValue1

typedef NS_ENUM(NSInteger, HogeStyle) { HogeFugaDefault, HogeFugaValue1, HogeFugaValue2, HogeFugaSubtitle};

ObjCHogeFugaValue1

複雑な例(Prefixが一致していない)

Page 19: Swiftのアプリ開発でハマったこと

enum型のメソッド引数や変数にenumで定義された定数以外を設定するとエラーになる

Page 20: Swiftのアプリ開発でハマったこと

typedef NS_ENUM(NSInteger, UIViewContentMode) { UIViewContentModeScaleToFill, ...}!self.view.contentMode = 0!// => ERROR Cannot convert the expression's type '()' to type 'UIViewContentMode'

Swiftの型は厳しいですね

Page 21: Swiftのアプリ開発でハマったこと

スカラー型のキャストはコンバージョンを使う

Page 22: Swiftのアプリ開発でハマったこと

let i: Int = Int(1.0)let n: NSInteger = NSInteger(1.0)!

let f: Float = Float(100)let d: Double = Double(100)let g: CGFloat = CGFloat(100)

Swiftではスカラー型のキャストはない

代わりにコンバージョンを利用

Page 23: Swiftのアプリ開発でハマったこと

let index: NSInteger = 1let width: CGFloat = 100let r = width * (CGFloat)index!

// => ERROR Consecutive statements on a line must be separated by ';'

ObjCライクなキャストはできない

Page 24: Swiftのアプリ開発でハマったこと

let someObjects: [AnyObject] = [ Movie(name: "2001: A Space", director: "Stan"), Movie(name: "Moon", director: "Duncan Jones"), Movie(name: "Alien", director: "Ridley Scott")]!for object in someObjects { let movie = object as Movie // Type Casting ! println("Movie: '\(movie.name)', dir. \(movie.director)") }

補足オブジェクト型はキャスト可能

Page 25: Swiftのアプリ開発でハマったこと

for movie in someObjects as [Movie] { println("Movie: '\(movie.name)', dir. \(movie.director)") }

配列をキャストするとコンパクトに書ける

Page 26: Swiftのアプリ開発でハマったこと

CGFloatとFloatまたはDoubleの演算

Page 27: Swiftのアプリ開発でハマったこと

import CoreGraphics!

typealias CGFloat = Float

CoreGraphicsにはCGFloatはFloatとエイリアスされている

Page 28: Swiftのアプリ開発でハマったこと

let index: NSInteger = 1let width: CGFloat = 100let r1 = width * Float(index)!

// => ERROR Could not find an overload for '*' that accepts the supplied arguments

CGFloatとFloatの演算

一見正しく動作しそうだがエラーになる

Page 29: Swiftのアプリ開発でハマったこと

なぜなら iPhone5s(arm64)をターゲットにビルドしているから

Page 30: Swiftのアプリ開発でハマったこと

このときCGFloatはSwiftのDoubleにエイリアスされる

Page 31: Swiftのアプリ開発でハマったこと

let index: NSInteger = 1let width: CGFloat = 100let r2 = width * Double(index)// => OK

iPhone5s(arm64)の場合はDoubleだとコンパイルできる

Page 32: Swiftのアプリ開発でハマったこと

let index: NSInteger = 1let width: CGFloat = 100let r = width * CGFloat(index)// => OK

CGFloatとの演算はCGFloatにコンバージョンしましょう

Page 33: Swiftのアプリ開発でハマったこと

ObjCのNSIntegerとSwiftのIntの演算

Page 34: Swiftのアプリ開発でハマったこと

typealias NSInteger = Int!

!

let i: Int = 1let n: NSInteger = 1let x: CGFloat = 3let y: Float = 3let w = i + Int(x) + Int(y) // => OKlet q = n + Int(x) + Int(y) // => OK!

if n == i { println("HERE!") // => OK}

Page 35: Swiftのアプリ開発でハマったこと

let u: NSUInteger = 1!

// ERROR => Use of undeclared type 'NSUInteger'; did you mean to use 'Int'?

NSUInteger は利用できません

Page 36: Swiftのアプリ開発でハマったこと

クロージャ型プロパティのオプショナルな書き方

Page 37: Swiftのアプリ開発でハマったこと

class Fuga { var completion: ( () -> () )?}

丸括弧で括ります

Page 38: Swiftのアプリ開発でハマったこと

ObjCのClass型をパラメータにとるメソッドにSwiftのClassを渡す方法

Page 39: Swiftのアプリ開発でハマったこと

@interface RKObjectMapping : RKMapping {+(instancetype)mappingForClass:(Class)objectClass}!!@implementation RKObjectMappingOp…{ return [mapping.objectClass new];}

渡したClass型がObjC側でnewされるケース

(例: Restkit)

Page 40: Swiftのアプリ開発でハマったこと

Swiftからどういう clazz を渡せばいいのか

class HogeModel: NSObject {}!!var clazz = ??? let mapping: RKObjectMapping = RKObjectMapping(forClass: clazz)

Page 41: Swiftのアプリ開発でハマったこと

var clazz: AnyClass = NSClassFromString(“WTDHogeModel”)!

// ERROR => EXC_BAD_INSTRUNCTION

失敗① NSClassFromStringで渡す

Page 42: Swiftのアプリ開発でハマったこと

var clazz: AnyClass = object_getClass(WTDHogeModel())!

!

// newでERROR[mapping.objectClass new];

失敗② object_getClassで渡す

Page 43: Swiftのアプリ開発でハマったこと

var clazz: NSObject.Type = WTDHogeModel.self let mapping: RKObjectMapping = RKObjectMapping(forClass: clazz) !!

// => OK

結論 NSObject.Typeを渡す

Page 44: Swiftのアプリ開発でハマったこと

シングルトンパターンを実装する3つの方法

Page 45: Swiftのアプリ開発でハマったこと

!

!

遅延初期化(lazy initialization)とスレッドセーフ(thread safety)が考慮された実装

Page 46: Swiftのアプリ開発でハマったこと

class Singleton { class var sharedInstance : Singleton { struct Static { static var onceToken : dispatch_once_t = 0 static var instance : Singleton? = nil } dispatch_once(&Static.onceToken) { Static.instance = Singleton() } return Static.instance! }}

dispatch_onceで定義

ObjCと同様の実装方法毎回これを書くにのは大変

Page 47: Swiftのアプリ開発でハマったこと

let _SingletonSharedInstance = Singleton()!class Singleton { class var sharedInstance : Singleton { return _SingletonSharedInstance }}

グローバル定数で定義

今後Swiftの言語仕様が変更され局所的グローバル変数が定義できるようになれば、この実装方法がもっともシンプル

Page 48: Swiftのアプリ開発でハマったこと

class Singleton { class var sharedInstance : Singleton { struct Static { static let instance : Singleton = Singleton() } return Static.instance }}

structのstatic定数で定義 (推奨)

Swiftのclassはstatic定数を利用できないので、structでネストしてstatic定数を保持

Page 49: Swiftのアプリ開発でハマったこと

Xcode6とSwift&iOS8のアプリ開発で踏んだ地雷たち

Page 50: Swiftのアプリ開発でハマったこと

コンパイルエラー XXXHeaderファイル has been

modified since the precompiled header

Page 51: Swiftのアプリ開発でハマったこと

fatal error: file ‘…/UIKit.framework/Headers /UIVisualEffectView.h’ has been modified since the precompiled header …

Page 52: Swiftのアプリ開発でハマったこと

対応方法 毎回なぜかなおる対応方法がまちまち !

- Xcode6再起動 - ビルドをクリーンする - DerivedDataを削除する - OSXを再起動する - Xcode6を入れなおす orz

Page 53: Swiftのアプリ開発でハマったこと

② IBOutletのStoryboardとのコネクションありが表示されない場合がある

Page 54: Swiftのアプリ開発でハマったこと

コンパイル後のアプリの挙動は正しく接続されている状態で動作していました

Page 55: Swiftのアプリ開発でハマったこと

③ Storyboardのファイルを開いてもXMLで表示される

Page 56: Swiftのアプリ開発でハマったこと

XML…

Page 57: Swiftのアプリ開発でハマったこと

明示的に開きましょう

Page 58: Swiftのアプリ開発でハマったこと

④ ソースコードハイライトと入力補完が効かなくなる

Page 59: Swiftのアプリ開発でハマったこと

たまに復活もしますw

Page 60: Swiftのアプリ開発でハマったこと

⑤ シミュレーターでアプリを起動しようとするとエラーになる

Page 61: Swiftのアプリ開発でハマったこと

Xcode6とシミュレーターを再起動したらなおりました。

Page 62: Swiftのアプリ開発でハマったこと

⑥ Xcode5とXcode6のシミュレーターで同時にアプリを起動できない

Page 63: Swiftのアプリ開発でハマったこと

どちらかのシミュレーターを終了しましょう

Page 64: Swiftのアプリ開発でハマったこと

⑦ switchと書くとXcodeがフリーズする

Page 65: Swiftのアプリ開発でハマったこと

Beta3ではまだ出ていないです

Page 66: Swiftのアプリ開発でハマったこと

⑧ 誤ってプロジェクトをXcode5で開いてStroyboardを開くとXcode6でStroyboardがおかしくなっている

Page 67: Swiftのアプリ開発でハマったこと

Xcode5で誤って開いたら何やらエラーが

ファイルが破壊されました。 git reset などでファイルを戻しましょう。

Page 68: Swiftのアプリ開発でハマったこと

Finderからプロジェクトファイルをダブルクリックして開くとXcode5で開かれることもあります。

Page 69: Swiftのアプリ開発でハマったこと

Xcode5を起動すると、Xcode6で作業していたプロジェクトを勝手に開く場合があります。

Page 70: Swiftのアプリ開発でハマったこと

予防策 !

1. gitなどで細かくコミットしてロールバックできるように !

2. Xcode6でプロジェクトを開いたらストーリボードを最終編集画面にして閉じない !

3. Xcode6を終了するときはプロジェクトを閉じてから終了する !

4. Xcode5を捨てるw

Page 71: Swiftのアプリ開発でハマったこと

iOS,Android Rails エンジニア

募集中

[email protected]興味がある方はこちらからご連絡ください

新しい技術にどんどん挑戦したい モバイルエンジニア・ウォンテッド!!

こちらからでもOKです

Page 72: Swiftのアプリ開発でハマったこと

おわり