self = [super init]的内存/指针行为

时间:2012-12-10 20:26:10

标签: objective-c pointers memory-management self

请原谅:我是初学者。我正在看另一个问题/答案,并遇到了这段代码:

SpinningView *spinner = [[SpinningView alloc] initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)]

//现在让我们来看看SpinningView的-initWithFrame:方法的实现

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    if (self)
    {
        self.backgroundColor = [UIColor clearColor];
    }

    return self;
}

我相信,在代码的第二部分中,self指向发送消息的实例,导致遇到“self”,即[Spin​​ningView alloc]的结果。 (或者不产生实例?)

所以,当你在第4行代码上调用self = [super initWithFrame:frame]时,你是不是要重新分配与“spinner”相关联的指针值?即,你是不是放弃了你在第一行分配的内存?或者编译器有人知道只是复制内存值而不是更改指针值?或者......什么??

谢谢!

2 个答案:

答案 0 :(得分:1)

这是obj-c对象的-init方法的标准习惯用法。这个想法是,从+alloc分配的内容无关紧要,只有从-init返回的内容才重要。现在,-init 通常只使用self中已分配的对象。但它不是必须的。可以自由地释放该对象并创建一个新对象。经典的例子是当你分配/初始化NSString*时,实际上并没有找回NSString*的实例,你会得到一个具体的子类。这是因为NSString*是“类群集”。因此,当您调用+alloc时,您将返回NSString*,但是当您调用-init时,它会释放该对象并重新分配其子类之一的对象,初始化该新对象,然后交给它回到你身边。

另一个例子是如果你有一个试图记忆自己的类。假设您有一个使用数字初始化的不可变类。您可以更改-init以重新使用该类的现有实例。这是一个例子(注意:不是线程安全的):

static NSDictionary *numberCache;

@interface MyNumber : NSObject
@property (readonly) int number;
- (id)initWithInt:(int)i;
@end

@implementation MyNumber
+ (void)initialize {
    if (self == [MyNumber class]) {
        numberCache = [[NSDictionary alloc] init];
    }
}

- (id)initWithInt:(int)i {
    // find ourself in the numberCache
    NSValue *val = [numberCache objectForKey:@(i)];
    if (val) {
        // yep, we exist. Release the just-allocated object
        [self release];
        // and retain the memoized object and stuff it back in self
        self = [[val nonretainedObjectValue] retain];
    } else if ((self = [super init])) {
        // nope, doesn't exist yet. Initialize ourself
        _number = i;
        // and stuff us into the cache
        val = [NSValue valueWithNonretainedObject:self];
        [numberCache setObject:val forKey:@(i)];
    }
    return self;
}

- (void)dealloc {
    // remove us from the cache
    [numberCache removeObjectForKey:@(_number)];
    [super dealloc];
}
@end

答案 1 :(得分:0)

@KevinBallard涵盖了大部分要点。我们需要self =的原因是因为init无法保证返回调用它的同一对象(它可能返回不同的对象或nil)。我将回答您的问题并扩展内存管理方面:

  

我相信,在代码的第二部分,自我指向   发送消息导致“自我”存在的实例   遇到了,即[Spin​​ningView alloc]的结果。

  

所以,当你在第4行调用self = [super initWithFrame:frame]时   代码,你不是重新分配与之关联的指针值   “微调”?

是。目前还不是spinnerspinner不存在)。您正在方法中重新分配指针变量self

  是的,你是不是放弃了你在第一次分配的内存   线?或者编译器只知道复制内存值   而不是改变指针值?或者......什么??

是。在MRC下,您只是重新分配指针,除了更改指针值之外,编译器不会执行任何操作。在ARC下,它更复杂,但在一天结束时,编译器在这种情况下就像在MRC下一样,即只重新指定指针。

如果你考虑一下,它并不是真的“放弃”记忆。按照惯例,您会看到init方法取得(“使用”)已经保留的对象的所有权(通常是对alloc的调用的返回结果),并返回保留的对象。但这两者不一定是同一个对象。因此,当您调用init方法时,其self已被保留,init方法拥有该方法,但随后调用[super init...],调用超类{{1} init上的方法,以便现在获取self拥有self所有权的所有权。作为回报,该超类的init会向您返回一个保留的实例,您将其分配给init。你并没有“放弃”self,因为你把它交给了超类的self方法,后者又负责管理它的内存(如果它想要返回别的东西就释放它)。