Swift – "无法找到名称为XXX的对象类"

11
我是一个新手Cocoa编程,以前从未接触过Objective-C。现在,我正在尝试通过阅读Aaron Hillegrass的书籍“Cocoa Programming for Mac OS X, 4e”,并使用Swift实现书中所有内容而不是Obj-C来学习它。到目前为止,一切都还好,但我在第8章(RaiseMan应用程序)遇到了障碍。

以下是书中的Objective-C代码:

头文件:

#import <Foundation/Foundation.h>

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

这里是实现

#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

您需要前往Interface Builder,获取一个Array Controller,将其指定为Person类,并将personName和expectedRaise添加为其键。
我重写了Swift中的Person类,如下所示:
import Cocoa

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

我已经按照要求翻译了内容:

并按照书中的指示将其连接到ArrayController。

Document文件中还有一些代码:

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

这是界面的样子(SO不允许我直接发布)https://www.dropbox.com/s/e5busxes9ex3ejd/Screenshot%202014-06-13%2019.02.37.png。当我试图运行应用程序并单击“添加员工”按钮时,控制台会显示以下错误:“RaiseMan [9290:303]无法找到名称为Person的对象类”。那么,我的问题是:我做错了什么?

+1,因为和我一样遇到了相同的问题!我以为自己疯了,用这本2008年的书在Swift中编写Cocoa应用程序。我看到我不是唯一一个通过艰难的方式学习好东西的人。 - Christopher J.
3个回答

16

简短回答:您需要在Interface Builder中指定类命名空间(模块名称):RaiseMan.Person


详细信息和其他选项:

这是因为Swift会为每个注入Objective-C运行时的类名称添加前缀,以避免名称冲突。前缀遵循这种约定:_TtC$$AppName%%ClassName,其中$$AppName 的长度,%%ClassName 的长度(有关更多信息,请参见此其他SO问题)。

因此,为了使数组控制器能够实例化 Person 类,您需要在Interface Builder中提供混淆后的名称:_TtC8RaiseMan6Person

另一个选项是使用@objc(<#name#>)属性为您的Swift类提供明确的Objective-C名称:

@objc(Person)
class Person: NSObject {
}

如果是这种情况,您可以将@objc属性中指定的名称(例如Person)提供给Interface Builder。有关更多详细信息,请参见《在Cocoa和Objective-C中使用Swift》指南。


这对于Cocoa绑定同样适用。在那里,您必须在“Object Controller”的“Class Name”字段中添加模块/命名空间名称。 - max
我自己也遇到了这个问题...虽然我是一名长期的iOS开发者,但对Cocoa完全不熟悉。我使用了显式的Obj-C类名来解决它,但第一种方法似乎更简洁,所以我想找出原因。请问我应该在IB中的哪个对象上设置它?我一直试图在不同的地方设置它(数组控制器、表列),但Xcode立即删除我设置的任何内容...谢谢! - Reid
在Xcode 7.2 / OSX 10.10.5下,我对My_App.ClassName没有太多的运气,但@objc变体确实非常好用。这只是一个数据点。 - green_knight
我必须使用显式的Objective-C名称才能使这个工作。 - hoboBob

0

如果我理解您的示例并假设您的init()方法属于Person类,则您需要将init()方法放在类括号内部。

此外,使用以下格式声明某种类型的变量:

var/let (name):(type)(optional)

因此,对于您的示例,Person类应该是这样的:

class Person {
    var personName: String
    var expectedRaise: Float?
    init() {...}
}

如果不需要,你不一定要从NSObject子类化;在Swift中,对象不必从NSObject(或另一个父类)子类化,如果它们不需要。而“Float?”表示它是可选浮点类型,这意味着它是一个可能有值的浮点数,也可能没有值,这取决于人们是否预计会涨薪水(或者您可能不想将其设置为可选项,而只需将值设置为0)。


今天早上我重新编写了我的Person类,现在它有一个初始化器,但问题仍然存在。 - anna_hope
你可以发布一下已经重写的Person类吗?还有你是如何声明其实例的呢? - BJ Miller

0
记住,如果您有多个构建目标,则创建的每个新类都需要添加到该构建目标中。 如果没有将其目标成员身份设置为构建目标,则Swift将找不到该类文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接