はじめに
Xcode6-beta5 で、
従来のObjectiveCで書かれたコードにSwift側からDelegate Objectを渡したのに何故かnilになる という現象に遭遇しました。
ObjectiveC側で weak ref でObjectを保持している場合、 明らかに set しているのに直後にはnil になっています。
悩んだ結果、よくわからないけど Swift側のObjectがNSObjectを継承しておけば良さそう です。
下記のStackOverflowも参考になると思います。
http://stackoverflow.com/questions/24824753/delegate-not-getting-set
以降、検証結果です。
検証
ObjectiveC 側
delegate
という Propertyを weak で保持するだけのObjectとします。
@interface SpikeWeakref : NSObject
@property (weak) id delegate;
@end
#import "SpikeWeakref.h"
@implementation SpikeWeakref
@end
Swift側の検証コード
先ほどの ObjectiveC側のdelegate プロパティに、
- 普通の Swift Class Object
- @objc を付けた Swift Class Object
- NSObject を継承した Swift Class Object
の3つをsetして、その直後getしてログに出力します。
普通であれば、如何に weakとはいえ nil にはなっていないはずです。
class SwiftObject {}
@objc class SwiftObjectAtObjcAnnotation {}
class SwiftObjectExtendsNSObject : NSObject {}
class SpikeMain {
let normal = SwiftObject()
let annotation = SwiftObjectAtObjcAnnotation()
let nsobject = SwiftObjectExtendsNSObject()
func main() {
let child = SpikeWeakref()
child.delegate = normal
logger.debug("child.delegate (SwiftObject): \(child.delegate)")
child.delegate = annotation
logger.debug("child.delegate (SwiftObjectAtObjcAnnotation): \(child.delegate)")
child.delegate = nsobject
logger.debug("child.delegate (SwiftObjectExtendsNSObject): \(child.delegate)")
child.delegate = SwiftObjectExtendsNSObject()
logger.debug("child.delegate (instant SwiftObjectExtendsNSObject): \(child.delegate)")
var z = SwiftObjectExtendsNSObject()
child.delegate = z
logger.debug("child.delegate (temp var of SwiftObjectExtendsNSObject): \(child.delegate)")
let childSwift = SpikeWeakrefSwift()
childSwift.delegate = normal
logger.debug("childSwift.delegate (SwiftObject): \(child.delegate)")
}
}
class SpikeWeakrefSwift {
weak var delegate: AnyObject?
}
実行結果
以下のようになります。
child.delegate (SwiftObject): nil
child.delegate (SwiftObjectAtObjcAnnotation): nil
child.delegate (SwiftObjectExtendsNSObject): <XXXX.SwiftObjectExtendsNSObject: 0x7fdc4ca24c30>
child.delegate (instant SwiftObjectExtendsNSObject): nil
child.delegate (temp var of SwiftObjectExtendsNSObject): <XXXX.SwiftObjectExtendsNSObject:0x7fdc4a70b000>
childSwift.delegate (SwiftObject): <XXXX.SwiftObjectExtendsNSObject: 0x7fdc4a70b000>
まとめると以下のようになります
普通の Swift Class Object
直後に nil になる
@objc を付けた Swift Class Object
直後に nil になる
NSObject を継承した Swift Class Object
Objectがあることが確認できる
NSObject を継承した Swift Class Object を 直接delegateにsetした場合
直後に nil になる
NSObject を継承した Swift Class Object を Local変数に代入した後 delegateにsetした場合
Objectがあることが確認できる
Swift Class が weak ref で delegate を持っている場合に普通のSwift Class Objectをsetした場合
Objectがあることが確認できる
さいごに
これが本来の仕様だとすると、結構気をつけないと危ないかもしれません。