后续操作以从[[类的alloc] INIT]返回nil(Followup to returning

2019-10-17 09:42发布

由于各种各样的后续从返回nil [类的alloc]初始化]好的做法? ,还有,我还没有看到任何讨论很多的情况下:如何处理失败了一些先决条件,才可以调用初始化旁边一个init?

例如,假设在此initWithStuff:传递零或一般没有价值传递给initWithValue方法:是一个绝对的失败,我们一定要回到零。

- (id)initWithStuff:(Stuff *)inStuff {
  if (!inStuff || ![inStuff hasValidValue])
  {
    // can't proceed to call initWithValue: because we have no value
    // so do what?
    return nil;
  }
  NSInteger value = [inStuff integerValue];
  return [super initWithValue:value];
}

也许更清楚的例子是,如果我们包裹指定初始化方法采用一个对象的指针,并抛出如果其通过零个例外。 我们一定要到初始化调用会导致异常短路。

我的猜测:任何初始化可能的手段,然后才返回nil之前释放自我。 如有必要,呼叫裸init或任何其他初始化,将工作完成把自成已知状态释放之前。

  // can't proceed to call super's initWithValue: because we have no value
  // so do what? do this:
  self = [super init]; // or initWithValue:0
  [self release];
  return nil;

如果没有这样的初始化,将没有有效数据的工作,我想人们会需要构建一些有效的,虚拟数据。 或者抱怨它的作者,直到然后就返回零,并与泄漏住:^)

此外,如何ARC影响的情况呢?

我的猜测:仍然完成任何初始化可能的手段,那么就返回nil。 你会觉得自己的设置可能是多余的,但在某些情况下,它不是。 在任何情况下,但它需要在那里沉默编译器警告。

  // can't proceed to call super's initWithValue: because we have no value
  // so do what? do this:
  self = [super init]; // finish init so ARC can release it having no strong references
  return nil;

是我猜错以任何方式?

Answer 1:

理想情况下,如果前提条件失败,你不叫[super init…] 你只要释放self (如果不使用ARC),并返回零:

- (id)initWithStuff:(Stuff *)stuff {
    if (!stuff || ![stuff isValid]) {
        [self release]; // if not using ARC
        return nil;
    }

    if (self = [super init]) {
        // initialization here
    }
    return self;
}

发布需要重新分配照顾self MRC下。 根据ARC,编译器会插入你释放。

但是,这种方法的潜在问题。 当你释放self (或当ARC释放它为你)时,系统将发送dealloc消息的对象。 和你dealloc方法将调用[super dealloc] 你可以抑制[super dealloc] MRC下,但你不能用ARC避免。

所以危险的是,你的超可能会认为它的实例变量中的一个已经初始化,并依靠其是初始值dealloc 。 例如,假设这是超:

@interface SomeSuperclass : NSObject
@end

@implementation SomeSuperclass {
    CFMutableBagRef bag;
}

- (id)init {
    if (self = [super init]) {
        bag = CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks);
    }
    return self;
}

- (void)dealloc {
    CFRelease(bag);
}

@end

这里的问题是, CFRelease要求其参数不为零。 因此,这将释放过程中崩溃,如果你不叫[super init]在你的子类。

考虑到这个问题,我不得不改变我最初的建议。 如果你知道你的超类的dealloc没有这类问题(因为,例如,它取消引用或将它们传递到之前检查指针CFRelease ),那么你可以放心地不能调用[super init]

如果你知道你的超类的dealloc是安全的,那么我的建议是,你移动你的前提出来的init ,进入一个类工厂方法。

换句话说,不把alloc/init为你的类的公共接口的一部分。 为创建实例的类方法:

// The class factory method.  Declare this in your header file.  This is how you
// or any user of this class should create instances.
+ (id)myObjectWithStuff:(Stuff *)stuff {
    if (!stuff || ![stuff isValid])
        return nil;

    // self here is the class object, so it's appropriate to send `alloc` to it.
    // You don't want to hardcode the class name here because that would break
    // subclassing.
    return [[self alloc] initWithStuff:stuff];
}

// This is now considered a private method.  You should not declare it in your
// header file, though in Objective-C you can't prevent the user from calling it
// if he's determined to.
- (id)initWithStuff:(Stuff *)stuff {
    // Precondition was already checked in myObjectWithStuff:.
    if (self = [super init]) {
        // initialization here...
    }
    return self;
}


文章来源: Followup to returning nil from a [[class alloc] init]