Resolving strong references between Swift and Objective-C classes – Using unowned and weak references from Swift to Objective-C classes

My Swift and SpriteKit exploration continues. At the moment I'm writing the collision handling code.

Rather than derive game objects from SKSpriteNode with each derived class containing the code for handling collisions with the other types of game objects I'm following something akin to a Component-Entity model.

I have per-game-object handler classes of which an instance of each is stored in the actual SKSpriteNode's userData dictionary. In turn each handler instance has a reference to the SKSpriteNode that references it. Given ARC is used this is a classical strong-reference chain which will prevent memory from being freed. The usual solution to this in Objective-C is to have one of the references be weak. In Swift there are two types of weak references: weak which is the same as in Objective-C and unowned (which I think is new). The difference is that an unowned reference can never be nil, i.e. it's optional whether a weak pointer reference an object but an unowned pointer must always reference something. As such the member variable is always defined using let and must be initialized, i.e. an init method is required.

The following code shows how I was intending to implement this. There is the strong reference from node.UserData to PhysicsActions and then the unowned reference back again from PhysicsActions.

class PhysicsActions
{
  unowned let node : SKSpriteNode

  init(associatedNode : SKSpriteNode)
  {
    // Store really weak (unowned) reference
    self.node = associatedNode
  }

  func onContact(other : PhysicsActions)
  {
     // Do stuff with node

  }
}

class func makeNode(imageNamed name: String) -> SKSpriteNode
{
  let node = SKSpriteNode(imageNamed: name)
  node.userData = NSMutableDictionary()
  // Store strong reference
  node.userData["action"] = makeActionFn(node)
  return node

}

However, when I went to use this code it crashed within the onContact method when it attempted to use the node. Changing this the reference type from unowned to weak fixed this, e.g.

weak let node : SKSpriteNode?

This verified that the rest of the code was ok so this seemed to look like another Swift/Objective-C interoperability issue. Firstly, I made a pure Swift example which is a simplified version from the The Swift Programming Language book.

class Foo
{
  var bar : Bar?

  func addBar(bar: Bar)
  {
    self.bar = bar
  }
}

class Bar
{
  unowned let foo : Foo
  init(foo : Foo)
  {
    self.foo = foo
  }

  func f()
  {
    println("foo:\(foo)")
  }
}

var foo : Foo? = Foo()
var bar = Bar(foo: foo!)
foo!.ç(bar)

bar.f()

Which works and results in:

foo:C14XXXUnownedTest3Foo (has 1 child)

Ok, not a fundamental problem but let's try having an unowned reference to an Objective-C class which is just like the real case as that's what SKSpriteNode is.

Foo2.h

@interface Foo2 : NSObject
@end

Foo2.m

@implementation Foo2

-(id)init
{
  return [super init];
}

@end

main.swift

class Bar2
{
  unowned let foo2 : Foo2
  init(foo2 : Foo2)
  {
    self.foo2 = foo2
  }

  func f()
  {
    println("foo2:\(foo2)")
  }
}

var foo2 = Foo2()
var bar2 = Bar2(foo2: foo2)
bar2.f()

Which when foo2.f() is invoked results in:

libswift_stdlib_core.dylib`_swift_abortRetainUnowned:
0x100142420:  pushq  %rbp
0x100142421:  movq   %rsp, %rbp
0x100142424:  leaq   0x17597(%rip), %rax       ; "attempted to retain deallocated object"
0x10014242b:  movq   %rax, 0x348be(%rip)       ; gCRAnnotations + 8
0x100142432:  int3   
0x100142433:  nopw   %cs:(%rax,%rax)

Again, changing unowned let foo2 : Foo2 to weak var foo2 : Foo2? works. 

I can't explain what the actual problem is but it looks like the enhanced weak reference support (unowned) only works with pure Swift classes. If you have cyclic references to Objective-C classes from Swift then don't use unowned. In fact writing the previous sentence led me to try the following:

let orig = Foo2()
unowned let other = orig
println("other:\(other)")
println("orig:\(orig)")

No cyclic references, just an ordinary reference counted instance of Foo2 (the Objective-C class) which is then assigned to an unowned reference. The final call to println will keep the instance around until the end. This crashes as per the previous example when the other variable is accessed. Changing the type assigned to orig from Foo2 (Objective-C) to Foo (Swift) make it work.

Therefore it seems unowned should not be used to refer to Objective-C classes, just Swift classes.



Resolving strong references between Swift and Objective-C classes – Using unowned and weak references from Swift to Objective-C classes

My Swift and SpriteKit exploration continues. At the moment I'm writing the collision handling code.

Rather than derive game objects from SKSpriteNode with each derived class containing the code for handling collisions with the other types of game objects I'm following something akin to a Component-Entity model.

I have per-game-object handler classes of which an instance of each is stored in the actual SKSpriteNode's userData dictionary. In turn each handler instance has a reference to the SKSpriteNode that references it. Given ARC is used this is a classical strong-reference chain which will prevent memory from being freed. The usual solution to this in Objective-C is to have one of the references be weak. In Swift there are two types of weak references: weak which is the same as in Objective-C and unowned (which I think is new). The difference is that an unowned reference can never be nil, i.e. it's optional whether a weak pointer reference an object but an unowned pointer must always reference something. As such the member variable is always defined using let and must be initialized, i.e. an init method is required.

The following code shows how I was intending to implement this. There is the strong reference from node.UserData to PhysicsActions and then the unowned reference back again from PhysicsActions.

class PhysicsActions
{
  unowned let node : SKSpriteNode

  init(associatedNode : SKSpriteNode)
  {
    // Store really weak (unowned) reference
    self.node = associatedNode
  }

  func onContact(other : PhysicsActions)
  {
     // Do stuff with node

  }
}

class func makeNode(imageNamed name: String) -> SKSpriteNode
{
  let node = SKSpriteNode(imageNamed: name)
  node.userData = NSMutableDictionary()
  // Store strong reference
  node.userData["action"] = makeActionFn(node)
  return node

}

However, when I went to use this code it crashed within the onContact method when it attempted to use the node. Changing this the reference type from unowned to weak fixed this, e.g.

weak let node : SKSpriteNode?

This verified that the rest of the code was ok so this seemed to look like another Swift/Objective-C interoperability issue. Firstly, I made a pure Swift example which is a simplified version from the The Swift Programming Language book.

class Foo
{
  var bar : Bar?

  func addBar(bar: Bar)
  {
    self.bar = bar
  }
}

class Bar
{
  unowned let foo : Foo
  init(foo : Foo)
  {
    self.foo = foo
  }

  func f()
  {
    println("foo:\(foo)")
  }
}

var foo : Foo? = Foo()
var bar = Bar(foo: foo!)
foo!.ç(bar)

bar.f()

Which works and results in:

foo:C14XXXUnownedTest3Foo (has 1 child)

Ok, not a fundamental problem but let's try having an unowned reference to an Objective-C class which is just like the real case as that's what SKSpriteNode is.

Foo2.h

@interface Foo2 : NSObject
@end

Foo2.m

@implementation Foo2

-(id)init
{
  return [super init];
}

@end

main.swift

class Bar2
{
  unowned let foo2 : Foo2
  init(foo2 : Foo2)
  {
    self.foo2 = foo2
  }

  func f()
  {
    println("foo2:\(foo2)")
  }
}

var foo2 = Foo2()
var bar2 = Bar2(foo2: foo2)
bar2.f()

Which when foo2.f() is invoked results in:

libswift_stdlib_core.dylib`_swift_abortRetainUnowned:
0x100142420:  pushq  %rbp
0x100142421:  movq   %rsp, %rbp
0x100142424:  leaq   0x17597(%rip), %rax       ; "attempted to retain deallocated object"
0x10014242b:  movq   %rax, 0x348be(%rip)       ; gCRAnnotations + 8
0x100142432:  int3   
0x100142433:  nopw   %cs:(%rax,%rax)

Again, changing unowned let foo2 : Foo2 to weak var foo2 : Foo2? works. 

I can't explain what the actual problem is but it looks like the enhanced weak reference support (unowned) only works with pure Swift classes. If you have cyclic references to Objective-C classes from Swift then don't use unowned. In fact writing the previous sentence led me to try the following:

let orig = Foo2()
unowned let other = orig
println("other:\(other)")
println("orig:\(orig)")

No cyclic references, just an ordinary reference counted instance of Foo2 (the Objective-C class) which is then assigned to an unowned reference. The final call to println will keep the instance around until the end. This crashes as per the previous example when the other variable is accessed. Changing the type assigned to orig from Foo2 (Objective-C) to Foo (Swift) make it work.

Therefore it seems unowned should not be used to refer to Objective-C classes, just Swift classes.



Injecting Singletons in Objective-C Unit Tests

I've promised to write this up a few times now. As I've just given another talk that covers it I thought it was time to make good on that promise.

The topic is the use of singletons in UIKit (and AppKit) and how that makes code using them hard to test. These APIs are riddled with singletons and you can't really avoid them. In case you need convincing that singletons are problematic take this contrived function:

NSString* makeWidget() {
    NSString* colour = 
        [[NSUserDefaults standardUserDefaults] stringForKey: @"defaultColour"];
    return [colour stringByAppendingString: @"Widget"];
}

NSUserDefaults is a singleton - the sole instance of which is returned when you call standardUserDefaults.

Monster1

A perturbing problem

Now consider how we might test this code. Obviously in an example this trivial there are various ways we could change the code to make the problem go away. Consider this a scaled down example of a problem that may be deeper in the code - perhaps a legacy code-base (or even some third party library!).

A naive test might set the "defaultColour" key in NSUserDefaults prior to calling makeWidget(). The problem with that is that the environment is left in a changed state after the test. Subsequent tests may now pick up a different value if they use NSUserDefaults. Worse: NSUserDefaults is backed by persistent storage that can potentially leave your whole user account in a changed state!

So, at the very least, we should restore the prior value at the end of the test. This leads to further problems: If the test fails, or an exception is otherwise thrown, the clean-up would not be called. So we'd need to wrap it in a @try-@finally too. Then, can we be sure we know what value to restore it to. It's probably nil - but if it's not the environment is still in a different state. So we should capture the prior value first and hold it in a variable.

Now what if you need to set more than one value. Or you change the keys used. We're starting to do a lot of bookkeeping just to compensate for the fact that a singleton is being used. Not only is it ugly but it's increasingly error prone.

Better if we can avoid this in the first place. If we have the option - prefer to pass dependencies in - rather than have your code reach out to these Dependency Singularities. In our example either pass in the default colour, or failing that, pass in NSUserDefaults.

NSString* makeWidget( NSUserDefaults* defaults ) {
    NSString* colour = [defaults stringForKey: @"defaultColour"];
    return [colour stringByAppendingString: @"Widget"];
}

At first this doesn't seem to buy us much. We still need an instance of NSUserDefaults. Even if we alloc-init it we'll get a copy of the global one. That's better but we'd still be dependent on the environment and have to take steps to compensate. And in other cases we may not even have that option

Monster2

If you can't make it - fake it!

We might not be able to create completely fresh instances of NSUserDefaults - but we can create instances of a stand-in class. Due to Objective-C's dynamic nature we don't even need to subclass - and we only have to implement the methods that are actually called - in this case stringForKey:. We could do that with a Mock Object. Or we can build our own Fake. Let's assume you've written a Fake called FakeUserDefaults, which contains an NSMutableDictionary, a means to populate it (perhaps via an initialiser) and an implementation of stringForKey: that looks the key up in the dictionary. Now we can test like this:

TEST_CASE() {
    id defaults =
        [[FakeUserDefaults alloc] initWithValue: @"Red" 
                                         forKey: @"defaultColour"];
    REQUIRE_THAT( makeWidget( defaults ), StartsWith( @"Red" ) );    
}

Great. That seems to tick all the boxes. We have complete control of the default value and we haven't perturbed our environment. No clean-up is required at the end of the test (not even memory, if we're using ARC)

Assuming you have the freedom to change the code under test, here, of course. If makeWidget() was buried deep in some legacy code, for example, it may not be feasible to make such a change (yet). Even if we can make the change it can be useful to be able to put the test in first to watch your back while you change it. If we need to leave the call to [NSUserDefaults standardUserDefaults] baked into the code under test for whatever reason what else can we do?

Monster3

To catch a singleton we must think like a singleton

What we'd like is that, when standardUserDefaults is called on NSUserDefaults deep in the bowels of the code under test, it returns an instance of our fake class instead - but only while we're testing. Again, due to Objective-C's dynamic nature we can achieve this. But it starts to get messier. It involves gritty low-level functions from objc/runtime.h. Can we package that away somewhere?

Of course we can! Enter TBCSingletonInjector. I've uploaded the code to GitHub, but there's actually not much to it. It exposes one public (class) method:

+(void) injectSingleton: (id) injectedSingleton
              intoClass: (Class) originalClass
            forSelector: (SEL)originalSelector
              withBlock: (void (^)(void) ) code;

The usage is best explained by example:

TEST_CASE() {
    id defaults =
        [[FakeUserDefaults alloc] initWithValue:@"Red" forKey:@"defaultColour"];

    [TBCSingletonInjector injectSingleton: defaults
                                intoClass: [NSUserDefaults class]
                              forSelector: @selector(standardUserDefaults)
                                withBlock: ^ {
            REQUIRE_THAT( makeWidget(), StartsWith( @"Red" ) );
        } ];
}

Magic! How does it work? It uses a technique known as "method swizzling" (Ruby or Pythonists know it as "monkey patching"). In short we replace a singleton accessor method (such as standardUserDefaults) with one we control (actually another, not otherwise exposed, class method of TBCSingletonInjector). More specifically we swap the two implementations. This is so we can swap them back again when we're done. Then we call the code block - all within a @try-@finally - so no matter what happens we always restore everything to its previous state.

What does the method we swap in do? It returns a global variable.

Wait, what? I thought globals and singletons were basically the same thing? Aren't we out of the frying pan into the fire?

In the war against singletons we must fight them with singletons! Well it's not all bad. This global is only in our test code and we have full control over it. It gets set to our "injected" singleton instance (and set back to nil at the end). It's not perfect - we can only use this implementation to handle one singleton at a time. I've not yet needed to handle more than one but I daresay the implementation could be extended to handle it.

Keep it clean

Since we've hand rolled our own fake class here (FakeUserDefaults) we can tidy things up further if we encapsulate the use of the singleton injector within it. Just adding a method like this should do the trick:

-(void) use:(void (^)(void) ) code
{
    [TBCSingletonInjector injectSingleton: self
                                intoClass: [NSUserDefaults class]
                              forSelector: @selector(standardUserDefaults)
                                withBlock: code ];
}

Now the test code becomes:

    FakeUserDefaults* defs = 
        [[FakeUserDefaults alloc] initWithValue: @"Red" 
                                         forKey: @"defaultColour"];
    [defs use:^{
            REQUIRE_THAT( makeWidget(), StartsWith( @"Red" ) );
         }];

Or, if you prefer, even:

    [[[FakeUserDefaults alloc] initWithValue: @"Red" 
                                      forKey: @"defaultColour"]
    	use:^{
            REQUIRE_THAT( makeWidget(), StartsWith( @"Red" ) );
         }];

Not too bad, really. But, still, prefer to avoid the singletons in the first place if you have the option.

Monster4

Mocking a monster

Rather than hand rolling a Fake you might prefer to use a Mock object too. I've found OCMock does the job well enough. I'm sure other mocking frameworks would do so at least as well. I prefer to use mocks when I want to test the behaviour, though. In this context that might equate to testing that some code under test sets a value in a singleton (e.g. sets a key in NSUserDefaults). The Singleton Injector works just as well for that, of course.

So there we have it. When you really have to deal with the beast you now have some tools to do so. If you do it please consider only doing so until you are able to replace the singularity with something better behaved instead.