4

Prior to WWDC 2014 I was learning Objective-C. I had created an "Elevator Simulator" app that exists simply for the purpose of my learning. When you click one of the seven buttons, it closes the elevator doors (animation), moves one level at a time towards the selected level (as indicated by a text label and button colouring) and then re-opens the doors.

Following WWDC and the announcement of Swift, I'm trying to re-create this app in Swift. So far I'm finding Swift much nicer to work with, but I've hit one major roadblock concerning unowned references. The app was launching fine until I implemented the feature for the text label and button colouring to set based on properties of the Elevator model on app launch. After implementing these features, the app always crashes on launch.

Eventually I narrowed down the issue to being caused on any call from the view controller to the Elevator model. After commenting out the call to my view controller method for updating the interface, the app launches fine again, and I can confirm that the issue is with calling the Elevator model simply by trying to call in the initialiser. The following code snippets reproduce the issue:

App Delegate:

var window: UIWindow?
let mainElevator = Elevator()

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
    window = UIWindow(frame: UIScreen.mainScreen().bounds)

    mainElevator.view = ViewController(elevator: mainElevator)
    window!.rootViewController = mainElevator.view

    window!.makeKeyAndVisible()
    return true
}

Elevator (model):

class Elevator: NSObject {

    var view: ViewController?
    var currentLevel = 1
    var newLevel: Int?
}

ViewController:

class ViewController: UIViewController {

    unowned let elevator: Elevator

    init(elevator: Elevator) {
        self.elevator = elevator
        super.init(nibName: nil, bundle: nil)
        //self.elevator.currentLevel = 3
    }
}

Note: I've emitted the other methods in these classes as they don't seem to have an impact on the issue. I have confirmed this by creating a similar scenario using a Person and CreditCard example (used as an example by Apple), which simply consist of the parts I've pasted above.

With that last line of ViewController commented out, the app launches fine (showing the view based on loadView() and viewDidLoad()), but if I uncomment it, the app crashes. If I change the reference type to weak and optional, it also works fine, but it shouldn't be weak, optional, or a variable. The Elevator will always exist (but not necessarily the view, due to multi-tasking), and it should be constant. This is exactly the kind of situation that Apple described in the Person/CreditCard scenario.

Also, if I remove self. from that last tine (therefore using the local version of elevator), it works fine. So the model isn't being deallocated, it's just the unowned reference that's not working.

Edit: Crash Report

libswift_stdlib_core.dylib`_swift_abortRetainUnowned:
0x1001c3980:  pushq  %rbp
0x1001c3981:  movq   %rsp, %rbp
0x1001c3984:  leaq   0x176a7(%rip), %rax       ; "attempted to retain deallocated object"
0x1001c398b:  movq   %rax, 0x792ce(%rip)       ; gCRAnnotations + 8
0x1001c3992:  int3   
0x1001c3993:  nopw   %cs:(%rax,%rax)        Thread 1: EXC_BREAKPOINT (code=EXT_1386_BPT, subcode=0x0)

1 Answers1

1

I guess it is a bug.

If your Elevator class doesn't inherit from NSObject, it works. Otherwise you get long error message.

class Elevator {

    var view: ViewController?
    var currentLevel = 1
    var newLevel: Int?
}
juniperi
  • 3,723
  • 1
  • 23
  • 30
  • Hmm, that's interesting. Yes it fixes the problem. I recall Apple saying "you don't need to subclass NSObject, but you can". I'm guessing the reason to do it would be to use the class in Objective-C specific functions? I'm just wondering if it's better to subclass or not. – James Fletcher Jun 14 '14 at 08:09
  • @JamesFletcher Someone alredy asked that question in SO: http://stackoverflow.com/questions/24057525/swift-native-base-class-or-nsobject – juniperi Jun 14 '14 at 08:17