Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift – "Cannot find object class with name"

Tags:

macos

swift

cocoa

I'm a newcomer to Cocoa programming, having never got into Objective-C. Now, I am trying to learn it with Swift by going through the Aaron Hillegrass book “Cocoa Programming for Mac OS X, 4e" and implementing everything there in Swift instead of Obj-C. It has been going okay so far, but I hit a roadblock in Chapter 8 (the RaiseMan application).

Here is the Objective-C code from the book:

The header:

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *personName;
    float expectedRaise;
}
@property (readwrite, copy) NSString *personName;
@property (readwrite) float expectedRaise;
@end

And here is the implementation

#import "Person.h"

@implementation Person

@synthesize personName;
@synthesize expectedRaise;

- (id)init
{
   self = [super init];
   if (self) {
      expectedRaise = 0.05;
      personName = @"New Person";
   }
   return self;
}

@end

You are then supposed to go to Interface Builder, get an Array Controller, specify Person as its class, and add personName and expectedRaise as its keys.

I rewrote the Person class in Swift as follows:

import Cocoa

class Person: NSObject {
    var personName = String()
    var expectedRaise = Float()
}

and connected it to the ArrayController as the book told me to.

There is also some code in the Document file:

init() {
    employees = NSMutableArray()
    println("hi")
    super.init()
    // Add your subclass-specific initialization here.
    var p = Person()
    p.personName = "New Person"
    p.expectedRaise = 0.05                               
}

Here is what the interface looks like (SO won't let me post it directly) https://www.dropbox.com/s/e5busxes9ex3ejd/Screenshot%202014-06-13%2019.02.37.png

When I try to run the app and click the "add employees" button, I get this error in the console:

"RaiseMan[9290:303] Cannot find object class with name Person"

So, my question is: what am I doing wrong?

like image 657
anna_hope Avatar asked Jun 14 '14 00:06

anna_hope


1 Answers

Short answer: you need to specify the class namespace (module name) in Interface Builder: RaiseMan.Person


Details and other options:

This is because Swift adds a prefix to the name of every class injected into the Objective-C runtime in order to avoid name collisions. The prefix follows this convention: _TtC$$AppName%%ClassName, where $$ is the length of AppName and %% is the length of ClassName (see this other SO question for more info).

So in order for the array controller to be able to instantiate the Person class, you need to provide the mangled name in Interface Builder: _TtC8RaiseMan6Person.

Another option is to provide an explicit Objective-C name for your Swift class by using the @objc(<#name#>) attribute:

@objc(Person)
class Person: NSObject {
}

In that case, you can provide the name specified in your @objc attribute to Interface Builder (e.g. Person). See the Using Swift with Cocoa and Objective-C guide for more details.

like image 106
Pascal Bourque Avatar answered Sep 20 '22 15:09

Pascal Bourque