为什么class-method需要自动释放,但实例方法不需要

时间:2017-12-14 08:31:39

标签: ios objective-c

+ (UIView *)getView
{
    UIView *view = [[UIView alloc] init];
    return view;
}

- (UIView *)getView
{
    UIView *view = [[UIView alloc] init];
    return view;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  __weak UIView *view1 = [self getView];
  __weak UIView *view2 = [SampleViewController getView];

  NSLog(@"%@, %@", view1, view2);    // view1 is null and view2 isn't null

  for (int i = 0; i < 1000; i++) {   // Wait
    NSLog(@"Waiting");
  }

  NSLog(@"%@, %@", view1, view2);    // view1 is null and view2 isn't null
}

我在viewDidLoad中测试它,它显示view1为null并且view2具有值

3 个答案:

答案 0 :(得分:1)

它们都被释放但是静态的稍后。

尝试添加更多代码:

    NSLog(@"%@, %@", view1, view2); // You already have this
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@, %@", view1, view2);
    });

第二次打印将在3秒后发生,并且应该显示两者都为空。

这很可能是非静态方法的编译优化,它不会在您的视图上使用自动释放池。静态的一个显然位于自动释放池中,并将在下一个运行循环中释放。

编辑:我在创建新项目后测试的完整代码:

@implementation ViewController

+ (UIView *)getView
{
    UIView *view = [[UIView alloc] init];
    return view;
}

- (UIView *)getView
{
    UIView *view = [[UIView alloc] init];
    return view;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    __weak UIView *view1 = [self getView];
    __weak UIView *view2 = [ViewController getView];

    NSLog(@"%@, %@", view1, view2);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"%@, %@", view1, view2);
    });
}

@end

更进一步:

我创建了一个视图子类,以便能够进行更多调试:

@interface MyView: UIView
@end

@implementation MyView
- (void)dealloc {
    NSLog(@"Deallocated");
}
@end

那么我们就有了:

+ (UIView *)getView
{
    UIView *view = [[MyView alloc] init];
    return view;
}

- (UIView *)getView
{
    UIView *view = [[MyView alloc] init];
    return view;
}

我放了一个dealloc方法,所以我可以设置一个断点init。第一个命中是viewDidLoad,例如被称为对象。这样就可以清楚地知道这个对象没有进行自动释放,但是ARC系统自动添加了[view release]。第二个电话就在它之后,并说它来自自动释放池。

答案 1 :(得分:0)

由于未知原因,编译器为DEBUG中的类方法添加了__autoreleasing属性作为返回指针。我认为这很糟糕,因为它可能导致发布中的不同行为。您应该向Apple报告此错误。

答案 2 :(得分:0)

+ (UIView *)getView
{
    UIView *view = [[MyView alloc] init];
    return view;
}

- (UIView *)getView
{
    UIView *view = [[MyView alloc] init];
    return view;
}
- (void)viewDidLoad {
    [super viewDidLoad];

    __weak UIView *view1;
    __weak UIView *view2;
    @autoreleasepool{
        view1 = [self getView];
        view2 = [SampleViewController getView];
        NSLog(@"%@ %@", view1, view2);
    };
}

view1和view2都有值。 autorelease-object将被添加到最近的自动释放池中,因此instance-method也使用autorelease。编译器可能会添加class-method返回的对象和instance-method在不同的autorelease-pool中返回的对象。