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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With