0

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

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”关联的指针值?即,你没有放弃你在第一行分配的内存吗?还是有人知道编译器只是复制内存值而不是更改指针值?或者是什么??

谢谢!

4

2 回答 2

1

-init这是obj-c 对象方法的标准习语。这个想法是,无论分配什么都+alloc无关紧要,-init重要的是返回什么。现在,通常-init只会使用. 但这不是必需的。释放该对象并创建一个新对象是自由的。经典的例子是当你分配/初始化一个你实际上并没有得到一个实例时,你得到了一个具体的子类。这是因为是一个“类集群”。因此,当您调用时,您会返回一个,但是当您调用它时,会释放该对象并重新分配其子类之一的对象,初始化该新对象,然后将其交还给您。selfNSString*NSString*NSString*+allocNSString*-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
于 2012-12-10T20:28:42.033 回答
0

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

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

是的

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

是的。不spinnerspinner无论如何此时都不存在)。您正在方法内重新分配指针变量self

即,你没有放弃你在第一行分配的内存吗?还是有人知道编译器只是复制内存值而不是更改指针值?或者是什么??

是的。在 MRC 下,您只是重新分配指针,编译器除了更改指针值之外什么也不做。在 ARC 下,它更复杂,但归根结底,在这种情况下,编译器只是在 MRC 下做同样的事情,即只是重新分配指针。

如果你仔细想想,这并不是真的“放弃”记忆。您会看到,按照惯例,init方法拥有(“使用”)一个已保留的对象,它们被调用(通常是调用的返回结果alloc),并且它们返回一个保留的对象。但这两个不必是同一个对象。因此,当您的init方法被调用时,它self已经被保留,并且该init方法拥有它,但随后它调用[super init...],它调用超类的init方法 on self,因此该方法现在拥有self您拥有的init所有权。作为回报,该超类init返回给您一个保留的实例,您将其分配给self. 你没有“放弃”self因为你把它交给了超类的init方法,而后者又负责管理它的内存(包括如果它想返回其他东西就释放它)。

于 2012-12-11T02:17:59.010 回答