SlideShare a Scribd company logo
Swift LT
@Wantedly
2014-07-17 yohei sugigami
杉上 洋平 (スギガミ ヨウヘイ)
GitHub: @susieyy
先月JOINしたばかりの新米プログラマー
!
!
!
Wantedlyでは高いQiita力が求められる :)
Swiftで2位
・Swiftのアプリ開発でハマった	

 こと 10個	

!
・Xcode6とSwiftのアプリ開発で	

 踏んだ地雷たち8個
アジェンダ
Xcode6で新規のアプリを開発した時に気づいたこと
をまとめます。アプリの仕様は以下のとおり。	

!
- 開発言語はSwift	

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

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

- Storyboardを利用	

- AutolayoutとSizeClassesを利用
開発環境は以下のとおり。	

!
- Xcode6はBeta2, 3を利用	

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

!
Beta2で開発していたら、Beta3が出ました \(^o^)/
Swiftのアプリ開発で
ハマったこと
以下の様なObjCメソッドにSwiftの
クロージャを渡す方法
@interface HogeFuga : NSObject	
+ (void) hogeUsingBlock:(id)bock;	
@end
ObjC id = Swift AnyObject
HogeFuga.hogeUsingBlock( { () -> () in	
println("Fuga")	
})
ERROR Type '() -> ()' does not
conform to protocol 'AnyObject'
var closures: AnyObject = { () in	
println("Fuga")	
}
ERROR Type '() -> ()' does not
conform to protocol 'AnyObject'
typedef void (^Block)();	
!
@interface HogeFuga (Wrapper)	
+ (void) hogeUsingBlockWrapper:(Block)block;	
@end	
!
@implementation HogeFuga (Wrapper)	
+ (void) hogeUsingBlockWrapper:(Block)block;	
{	
[HogeFuga hogeUsingBlock:block];	
}	
@end
ObjCで型を明示したブロックを	

持つメソッドでラップする
NSObject#descriptionをオーバーラ
イドする
②
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
class Hoge: NSObject {	
var name: String?	
var note: String?	
	
override var description: String! {	
get {	
return "Name = (self.name), 	
			 	 	 	 	 	 	 	 Note = (self.note)"	
}	
}	
}	
プロパティのオーバーライドする
ObjCのenum値をSwift記法で記載
する方法がわからない
③
Swift	
UIViewAutoresizing.FlexibleLeftMargin
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {	
UIViewAutoresizingNone = 0,	
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,	
…	
}
ObjC	
UIViewAutoresizingFlexibleLeftMargin
わかりやすい例
Swift	
UIViewAnimationOptions.LayoutSubviews
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {	
UIViewAnimationOptionLayoutSubviews = 1 << 0,	
UIViewAnimationOptionAllowUserInteraction = 1 << 1,	
…	
}
ObjC	
UIViewAnimationOptionLayoutSubviews
許容範囲な例
Swift	
HogeStyle.FugaValue1
typedef NS_ENUM(NSInteger, HogeStyle) {	
HogeFugaDefault,	
HogeFugaValue1,	
HogeFugaValue2,	
HogeFugaSubtitle	
};
ObjC	
HogeFugaValue1
複雑な例(Prefixが一致していない)
enum型のメソッド引数や変数に
enumで定義された定数以外を設定
するとエラーになる
④
typedef NS_ENUM(NSInteger, UIViewContentMode) {	
UIViewContentModeScaleToFill,	
...	
}	
!
self.view.contentMode = 0	
!
// => ERROR Cannot convert the expression's type
'()' to type 'UIViewContentMode'	
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ではスカラー型のキャストはない	

代わりにコンバージョンを利用
let index: NSInteger = 1	
let width: CGFloat = 100	
let r = width * (CGFloat)index	
!
// => ERROR Consecutive statements on
a line must be separated by ';'
ObjCライクなキャストはできない
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)")	
}	
補足

オブジェクト型はキャスト可能
for movie in someObjects as [Movie] {	
println("Movie: '(movie.name)', 	
			 	 	 	 	 	 	 dir. (movie.director)")	
}
配列をキャストするとコンパクトに書ける
CGFloatとFloatまたはDoubleの演算
⑥
import CoreGraphics	
!
typealias CGFloat = Float
CoreGraphicsにはCGFloatはFloatとエイリア
スされている
let index: NSInteger = 1	
let width: CGFloat = 100	
let r1 = width * Float(index)	
!
// => ERROR Could not find an overload
for '*' that accepts the supplied
arguments
CGFloatとFloatの演算	

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

iPhone5s(arm64)をターゲットにビ
ルドしているから
このときCGFloatはSwiftのDouble
にエイリアスされる
let index: NSInteger = 1	
let width: CGFloat = 100	
let r2 = width * Double(index)	
// => OK
iPhone5s(arm64)の場合はDoubleだとコン
パイルできる
let index: NSInteger = 1	
let width: CGFloat = 100	
let r = width * CGFloat(index)	
// => OK
CGFloatとの演算はCGFloatにコンバー
ジョンしましょう
ObjCのNSIntegerとSwiftのIntの演
算
⑦
typealias NSInteger = Int	
!
!
let i: Int = 1	
let n: NSInteger = 1	
let x: CGFloat = 3	
let y: Float = 3	
let w = i + Int(x) + Int(y) // => OK	
let q = n + Int(x) + Int(y) // => OK	
!
if n == i {	
println("HERE!") // => OK	
}
let u: NSUInteger = 1	
!
// ERROR => Use of undeclared type
'NSUInteger'; did you mean to use
'Int'?
NSUInteger は利用できません
クロージャ型プロパティのオプ
ショナルな書き方
⑧
class Fuga {	
var completion: ( () -> () )?	
}
丸括弧で括ります
ObjCのClass型をパラメータにとる
メソッドにSwiftのClassを渡す方法
⑨
@interface RKObjectMapping : RKMapping {	
+(instancetype)mappingForClass:(Class)objectClass	
}	
!
!
@implementation RKObjectMappingOp…	
{	
return [mapping.objectClass new];	
}
渡したClass型がObjC側でnewされるケース	

(例: Restkit)
Swiftからどういう clazz を渡せばいいのか
class HogeModel: NSObject {	
}	
!
!
var clazz = ???

let mapping: RKObjectMapping =
RKObjectMapping(forClass: clazz)
var clazz: AnyClass =
NSClassFromString(“WTDHogeModel”)	
!
// ERROR => EXC_BAD_INSTRUNCTION
失敗①	

NSClassFromStringで渡す
var clazz: AnyClass =
object_getClass(WTDHogeModel())	
!
!
// newでERROR	
[mapping.objectClass new];
失敗②	

object_getClassで渡す
var clazz: NSObject.Type = WTDHogeModel.self

let mapping: RKObjectMapping =
RKObjectMapping(forClass: clazz) 	
!
!
// => OK
結論	

NSObject.Typeを渡す
シングルトンパターンを実装する
3つの方法
⑩
!
!
遅延初期化(lazy initialization)とスレッド
セーフ(thread safety)が考慮された実装
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と同様の実装方法

毎回これを書くにのは大変
let _SingletonSharedInstance = Singleton()	
!
class Singleton {	
class var sharedInstance : Singleton {	
return _SingletonSharedInstance	
}	
}
グローバル定数で定義
今後Swiftの言語仕様が変更され局所的グ
ローバル変数が定義できるようになれば、
この実装方法がもっともシンプル
class Singleton {	
class var sharedInstance : Singleton {	
struct Static {	
static let instance : Singleton = Singleton()	
}	
return Static.instance	
}	
}
structのstatic定数で定義 (推奨)
Swiftのclassはstatic定数を利用できないの
で、structでネストしてstatic定数を保持
Xcode6とSwift&iOS8
のアプリ開発で踏ん
だ地雷たち
コンパイルエラー	

XXXHeaderファイル has been
modified since the precompiled header
①
fatal error: file ‘…/UIKit.framework/
Headers /UIVisualEffectView.h’ has
been modified since the precompiled
header …
対応方法	

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

!
- Xcode6再起動	

- ビルドをクリーンする	

- DerivedDataを削除する	

- OSXを再起動する	

- Xcode6を入れなおす orz
②
IBOutletのStoryboardとのコネク
ションありが表示されない場合が
ある
コンパイル後のアプリの挙動は正しく接続
されている状態で動作していました
③
Storyboardのファイルを開いても
XMLで表示される
XML…
明示的に開きましょう
④
ソースコードハイライトと入力補
完が効かなくなる
たまに復活もしますw
⑤
シミュレーターでアプリを起動し
ようとするとエラーになる
Xcode6とシミュレーターを再起動
したらなおりました。
⑥
Xcode5とXcode6のシミュレーター
で同時にアプリを起動できない
どちらかのシミュレーターを終了
しましょう
⑦
switchと書くとXcodeがフリーズす
る
Beta3ではまだ出ていないです
⑧
誤ってプロジェクトをXcode5で開
いてStroyboardを開くとXcode6で
Stroyboardがおかしくなっている
Xcode5で誤って開いたら何やらエラーが
ファイルが破壊されました。	

git reset などでファイルを戻しましょう。
Finderからプロジェクトファイルを
ダブルクリックして開くとXcode5
で開かれることもあります。
Xcode5を起動すると、Xcode6で作
業していたプロジェクトを勝手に
開く場合があります。
予防策	

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

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

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

!
4. Xcode5を捨てるw
iOS,Android
Rails エンジニア
募集中
hiring@wantedly.com
興味がある方はこちらからご連絡ください
新しい技術にどんどん挑戦したい
モバイルエンジニア・ウォンテッド!!
こちらからでもOKです
おわり

More Related Content

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