15

我来自 Java 背景,正在学习 Objective C。我正在尝试创建一个具有字符串数组和成员函数来修改数组的类。我的代码如下所示:

@implementation TAWChapter

@synthesize mSubject;

@synthesize mItems;

- (id) init{
    self.mItems = [[NSMutableArray alloc] init];
    return self; 
}

- (void) setSubject:(NSString *)subject{
    self.mSubject = subject; 
}

- (void) addItem:(NSString *)item{
    [self.mItems addObject:@"asdf"]; 
}

@end

这没有用。我有一个"[__NSArrayI addObject:]: unrecognized selector sent to instance "和一个"NSInvalidArgumentException"。在互联网上搜索后,我将构造函数中的单行更改为:

self.mItems = [self.mItems init];

它奏效了,但为什么呢?从 Java 开发人员的角度来看,第一个比第二个更有意义。而且我还有另一行,它与第一行相同,但它正在工作(不在构造函数中)。有人可以向我解释一下吗?

4

4 回答 4

31
  1. 首先,您应该遵守 Objective-C 编码约定。在 Objective-C 中,类没有构造器,它们有初始化器。在 Objective-C 中,初始化器调用超类的初始化器,所以它应该是这样的:

    - init
    {
        self = [super init];
        if (!self) return nil;
    
        // set up other stuff here 
    
        return self;
    }
    
  2. 其次,除非您使用 ARC,否则您可能会遇到内存泄漏。初始化程序的第一行将您拥有的对象分配给也可能获得所有权的属性。你应该使用:

    // property takes care of ownership
    self.mItems = [NSMutableArray array];
    

    或者:

    // assign to instance variable directly with owned object
    mItems = [[NSMutableArray alloc] init];
    

    Apple 有时不鼓励在初始化程序中使用访问器方法,因为它可能会摆弄 KVO 之类的东西,但一致地使用访问器方法可以确保正确的对象所有权和内存管理。

  3. 通过将初始化程序中的行更改为:

    self.mItems = [self.mItems init];
    

    什么都不做。当你的初始化方法被调用时(通常是在它被分配之后),所有的实例变量都被自动设置为 nil。所以你正在做的只是:

    self.mItems = [nil init];
    

    这只是:

    self.mItems = nil;
    

    并且,不要在init没有先分配实例的情况下使用,并且不要init多次使用。

  4. 如果您不让超类自行初始化,那么它可能会在其他方面表现为问题。进行构建和分析并确保您已修复分析器指出的任何问题。

于 2012-05-06T23:20:00.213 回答
7

由于objective-c 是c 的超集,它基本上是带有一些“OO”语法糖的c。在您可以创建(或使用!)一个对象之前,您必须在堆中为其分配空间。你用[Class alloc]. 下一步是对该空间的初始化。alloc 返回指向堆中该空间的指针,您使用 init 对其进行初始化;)

所以你打电话Class *myObjc = [[Class alloc] init];

如果您使用继承(因为您从 NSOBject 继承,您就这样做了),您必须确保您的超类正确初始化了所有内容,这就是对 super 的调用。为确保您不会收到运行时错误,请检查 self != nil,您使用 if(self) 隐式执行此操作

self.mItems = [self.mItems init]; // doesn't do anything, since you call the getter for mItems with self.mItems and try to init. then you try to set mItmes to itself. 

使用此代码:

@implementation TAWChapter

@synthesize mSubject, mItems;

- (id)init
{
    self = [super init];
    if (self) {
        mItems = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void) setSubject:(NSString *)subject{
    mSubject = subject; 
}

- (void) addItem:(NSString *)item{
    [mItems addObject:item]; 
}

@end
于 2012-05-06T23:05:34.923 回答
4

您应该在您的方法中调用super并将其结果分配给:selfinit

- (id)init
{
    self = [super init];
    if (self) {
        self.mItems = [[NSMutableArray alloc] init];
    }
    return self;
}
于 2012-05-06T23:02:07.897 回答
2

另一种方法是从 NSArray 创建 NSMutableArray:

NSMutableArray *myMutableArray = [NSMutableArray arrayWithArray:myArray];
于 2015-04-15T23:30:25.923 回答