スカラー型のキャストはコンバージョンを使う
Swiftではスカラー型のキャスト(Casting
)はありません。その代わりにコンバージョン(Conversion
)を利用します。
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)
ObjCライクなキャストはできない
ObjCのようなキャスト構文は文法エラーになります。
let index: NSInteger = 1
let width: CGFloat = 100
let r = width * (CGFloat)index
// => ERROR Consecutive statements on a line must be separated by ';'
補足
オブジェクト型はキャスト可能です。
CGFloatとFloatまたはDoubleの演算でエラーになる場合がある
Swiftで扱うCGFloat
はビルドするアーキテクチャによってエイリアスが異なります。
シミュレーターがiPhone5s
(arm64)とiPhone5
,iPhone4s
(armv7, armv7s)では挙動が変わります。
アーキテクチャ | CGflotのエイリアス |
---|---|
arm64 | Double |
armv7, armv7s | Float |
一見、コンパイルが通りそうですがiPhone5s
シミュレーターでコンパイルするとエラーになります。
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
この場合は、Double
でコンバージョンすると演算可能です。
let index: NSInteger = 1
let width: CGFloat = 100
let r2 = width * Double(index)
// => OK
CGFloat
との演算は常ににCGFloat
にコンバージョンして演算することで、この問題を回避できます。
let index: NSInteger = 1
let width: CGFloat = 100
let r = width * CGFloat(index)
// => OK
ObjCのNSIntegerとSwiftのIntの演算
NSInteger
とSwiftのInt
はtypealias
された同じ型です。
// typealias NSInteger = Int
let x: CGFloat = 3
let y: Float = 3
let i: Int = 1
let n: NSInteger = 1
let w = i + Int(x) + Int(y) // => OK
let q = n + Int(x) + Int(y) // => OK
if n == i {
NSLog("HERE!") // => OK
}
SwiftではNSUInteger
を利用できません。
let u: NSUInteger = 1
// ERROR => Use of undeclared type 'NSUInteger'; did you mean to use 'Int'?
ObjCのid型をパラメータにとるメソッドにSwiftのクロージャを渡す方法
以下の様なObjCメソッドにSwiftのクロージャを渡す方法です。
@interface HogeFuga : NSObject
+ (void) hogeUsingBlock:(id)bock;
@end
ObjCのid
型はSwiftのAnyObject?
型と同義です。
クロージャは対応した型を有するのでAnyObject
型にはなりません。
よってid
型にクロージャを代入できない問題が発生します。
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'
解決策はObjCで型を明示したブロックを持つメソッドでラップします。
typedef void (^BlockHogeWrapper)();
@interface HogeFuga (Wrapper)
+ (void) hogeUsingBlockWrapper:(BlockHogeWrapper)block;
@end
@implementation HogeFuga (Wrapper)
+ (void) hogeUsingBlockWrapper:(BlockHogeWrapper)block;
{
[HogeFuga hogeUsingBlock:block];
}
@end
NSObject#descriptionをオーバーライドする
NSObject#description
のオーバーライドはメソッドをオーバーライドするかと思いきや、プロパティのオーバーライドになります。
class Hoge: NSObject {
var name: String?
var note: String?
override var description: String! {
get {
return "Name = \(self.name), Note = \(self.note)"
}
}
}
メソッドをオーバーライドしようするとエラーになります。
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 Fuga {
var completion: ( () -> () )?
}
ObjCのenum値をSwift記法で記載する方法がわからない
Swiftではenum値を記述するにはObjCと異りなり、enum型 ドット enum値
の文法になります。
この記述
記述方法がわかりやすい例
enum型とPrefixに値を分割できます。
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
…
}
// ObjC
UIViewAutoresizingFlexibleLeftMargin
// Swift
UIViewAutoresizing.FlexibleLeftMargin
記述方法の差異が少ない例
enum型と値のPrefixが一部(複数形のs)異なります。
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
UIViewAnimationOptionLayoutSubviews = 1 << 0,
UIViewAnimationOptionAllowUserInteraction = 1 << 1,
…
}
// ObjC
UIViewAnimationOptionLayoutSubviews
// Swift
UIViewAnimationOptions.LayoutSubviews
記述方法がわかりにくい例
enum型と値のPrefixがPrefixが一致していない場合です。
一致している部分のPrefixで分割しています。
typedef NS_ENUM(NSInteger, HogeStyle) {
HogeFugaDefault,
HogeFugaValue1,
HogeFugaValue2,
HogeFugaSubtitle
};
// ObjC
HogeFugaValue1
// Swift
HogeStyle.FugaValue1
enum型のメソッド引数や変数にenumで定義された定数以外を設定するとエラーになる
NSIntegerで定義されたenum型にNSInteger型の値(数値)を直接代入するとコンパイルエラーになります。
typedef NS_ENUM(NSInteger, UIViewContentMode) {
UIViewContentModeScaleToFill,
...
}
self.view.contentMode = 0
// => ERROR Cannot convert the expression's type '()' to type 'UIViewContentMode'
ObjCのClass型をパラメータにとるメソッドにSwiftのClassを渡す方法 (Restkit)
Class型をパラメータにとるメソッドにSwiftのClassを代入し、そのClassがObjC側でnewされるケースです。
@interface RKObjectMapping : RKMapping
{
// クラス型を引数にとる
+ (instancetype)mappingForClass:(Class)objectClass
}
...
@implementation RKObjectMappingOp …
{
// 渡したクラス型でnewされる
return [mapping.objectClass new];
}
NSObject.Type
型を代入すれば、うまくObjC側でもnewできました。
class HogeModel: NSObject {
}
var clazz: NSObject.Type = WTDHogeModel.self
let mapping: RKObjectMapping = RKObjectMapping(forClass: clazz)
以下のObjC由来のClassの取得方法で代入するとエラーになり,
うまくできませんでした。
// newするとERROR
var clazz: AnyClass = object_getClass(WTDHogeModel())
// ERROR => EXC_BAD_INSTRUNCTION
var clazz: AnyClass = NSClassFromString("WTDHogeModel")