12
12

More than 5 years have passed since last update.

ObjectiveCで記述されたweak変数にswiftからObjectを渡すときはNSObjectを継承しておかないといけない?

Posted at

はじめに

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とします。

SpikeWeakref.h
@interface SpikeWeakref : NSObject
@property (weak) id delegate;
@end
SpikeWeakref.m
#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があることが確認できる

さいごに

これが本来の仕様だとすると、結構気をつけないと危ないかもしれません。

12
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12