Unmanaged issues in Swift Beta 5

The following Unmanaged call breaks in Swift Beta 5.

import Foundation

var obj = NSObject()
var unretainedRefToObject = Unmanaged.passUnretained(obj)

Apparently, the compiler is unhappy:

Stored value type does not match pointer operand type!
  store %CSo8NSObject* %0, %objc_object** %.targetPtr._value, align 8, !dbg !879
 %objc_object*LLVM ERROR: Broken function found, compilation aborted!
Command /Applications/Xcode6-Beta5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1

Workaround (hack)

We’re using this workaround which stores a COpaquePointer:

import Foundation

var obj = NSObject()
var opaquePointerToUnretainedRefToObj = Unmanaged.passUnretained(obj).toOpaque()

Using the reference now requires one more step (and associated type bookkeeping):

var value = Unmanaged<NSObject>.fromOpaque(opaquePointerToUnretainedRefToObj).takeUnretainedValue()

Key Value Observation in Swift Beta 5

The recently released beta 5 of XCode includes the sizable number of breaking changes. Its now easier to get key value observation (KVO) working with Swift.

Suppose we have a class Publisher that inherits from NSObject and we want to observe changes to it’s property someProperty, we need to use the new keyword dynamic on the property to get KVO to work:

 class Publisher : NSObject {
    dynamic var someProperty : Int = 100 { 
      didSet { println("didSet \(someProperty)") } 
    }

    override var description: String { 
      return "Publisher:{someProperty: \(someProperty)}" 
    }
}

Let’s define a Subscriber which will listen to property changes:

class Subscriber : NSObject  {
    var callback: ()->()

    init(callback: ()->()) {
      self.callback = callback
    }

    override func observeValueForKeyPath(keyPath: String!,
      ofObject object: AnyObject!,
      change: [NSObject : AnyObject]!, 
      context: UnsafeMutablePointer<()>) {
        println("Subscriber: observeValueForKey: \(keyPath), \(object)")
        self.callback()
    }
  }

Hook up and test (full listing here):

func testCallbackOnChange() {
    var called = false
    var pub = Publisher()
    var sub = Subscriber(callback: { called = true } )
    pub.addObserver(sub, forKeyPath: "someProperty", 
      options: NSKeyValueObservingOptions.New, context: nil)
    XCTAssert(called == false, "Shouldn't receive initial callback")
    pub.someProperty = 101
    XCTAssert(called, "Should receive callback on new value")
    println("printing pub: \(pub)") //this prints nothing!!
    println("printing pub.description: \(pub.description)") //sure, this works
    pub.removeObserver(sub, forKeyPath: "someProperty")
}

What happened to .description?

Oddly enough, after an initial KVO trigger (pub.someProperty=101), println refuses to invoke Publisher.description. Bug?