自身的内存/指针行为 = [超级初始化]



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

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",即[SpinningView alloc]的结果。(或者这不会产生实例?

因此,当您在第 4 行代码上调用 self = [super initWithFrame:frame] 时,您不是重新分配与"spinner"关联的指针值吗?即,您没有放弃在第一行分配的内存吗?还是编译器知道只是复制内存值而不是更改指针值?或。。。什么??

谢谢!

这是 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

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

我相信,在代码的第二部分,self 指向 消息发送到的实例,导致"self"是 遇到,即[旋转视图分配]的结果。

是的

所以,当你在第 4 行调用 self = [super initWithFrame:frame] 的代码,您是否没有重新分配与 "陀螺"?

是的。不是spinner(反正此时spinner不存在)。您将在方法内部重新分配指针变量self

即,您是否没有放弃在第一个中分配的内存 线?还是编译器某人知道只是为了复制内存值 而不是更改指针值?或。。。什么??

是的。在 MRC 下,您只是重新分配指针,编译器除了更改指针值外不执行任何操作。在 ARC 下,它更复杂,但归根结底,编译器在这种情况下只是做与 MRC 下相同的操作,即只是重新分配指针。

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

最新更新