2

It appears that objc_setAssociatedObject causes objects to be released early.

I followed the method mentioned here to set the association.

import ObjectiveC

// Define a variable whose address we'll use as key.
// "let" doesn't work here.
var kSomeKey = "s"

…

func someFunc() {
    var value = MyOtherClass()
    objc_setAssociatedObject(target, &kSomeKey, value, UInt(OBJC_ASSOCIATION_RETAIN))

    let assocValue : AnyObject! = objc_getAssociatedObject(target, &kSomeKey)
}

This results in the object being released during the objc_setAssociatedObject call. As you can see by this stacktrace.

[MyOtherClass dealloc]
_objc_object::sidetable_release(bool)
_object_set_associative_reference
MyApp.MyClass.someFunc()

I originally thought it might have had something to do with swift classes so I also tried standard Objective-C classes and deinit or dealloc are called during the objc_setAssociatedObject call.

Further adding to my confusion is that objc_getAssociatedObject appears to return a valid object and I can access it variables without error.

Is this a swift bug or have I used objc_setAssociatedObject incorrectly?

I am using Xcode6 beta5 in case that is relevant.

Community
  • 1
  • 1
nacross
  • 2,013
  • 2
  • 25
  • 37
  • 1
    Are you sure there isn't already an associated object set for that key? It looks like an existing `MyOtherClass` instance is being replaced with a new instance. The old instance is deallocated because there are no other references to it. – Darren Aug 21 '14 at 18:19
  • I am reasonably confident that what you are suggesting is not the case, but will review the code again once I upgrade to beta6 and retest, as the behaviour you highlighted would be explained by that. – nacross Aug 24 '14 at 06:23
  • @Darren thanks for your help, it turns out that this was the issue after all. I had made the faulty assumption that the "target" was different every time, when in some scenarios the same "target" had different values set for it, causing the previously set object to be released. If you would like to write up your comment as an answer, I would like to accept it. – nacross Aug 24 '14 at 10:25

1 Answers1

0

I guess your code would not even compile, because you are using "value" twice as a constant name.

This works fine as an AppDelegate in beta 6:

import ObjectiveC

var kSomeKey = "this_is_a_key"

class MyOtherClass {
    var foo = "bar"

    deinit {
        println("deinit")
    }
}

@UIApplicationMain
class AppDelegateTest: UIResponder, UIApplicationDelegate {

    func someFunc() {
        var value = MyOtherClass()
        objc_setAssociatedObject(self, &kSomeKey, value, UInt(OBJC_ASSOCIATION_RETAIN))

        let value2: AnyObject! = objc_getAssociatedObject(self, &kSomeKey)

        println("type of is \(_stdlib_getTypeName(value2))")

        let value3 = value2 as MyOtherClass

        println("other is " + value3.foo)

        println("end of someFunc()")
    }


    func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
        self.someFunc()

        return true
    }
}

I barely changed anything and the deinit method is never called.

Klaas
  • 22,394
  • 11
  • 96
  • 107
  • I have updated my code sample to remove the compile error. This was censored version of my own code. The duplicate value variable name was unintentional. I will attempt to reproduce it again in beta6 soon. – nacross Aug 24 '14 at 06:14