目标C类方法返回的值,分配给弱/强属性(objective c class method retur

2019-07-04 14:19发布

我现在面临一个位涉及弱和强性能的困惑。 为了简便起见,我将不包括整个代码。

我创建它返回一个UIView对象的类的便利方法,以及我实现它在一个UIView类别作为替代子类。

@implementation UIView (CSMonthView)    

+ (UIView *)monthViewFromDateArray:(NSArray *)arrayOfAllShiftsAndEvents withNibOwner:(id)owner selectedDate:(NSDate *)selectedDate withCompletionHandler:(void(^)(CSCalendarButton *selectedButton))block
{   // .. do some stuff
    // Create an instance of UIView
    UIView *monthView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320.0, 200.0)];

    // Create UIButtons and set the passed down 'owner' value, as the target for an
    // action event.

    // Add UIButton as subviews to monthView....

    return monthView;
}

我要指出的是,方法内我没有什么指向monthView。

现在的“主人”,这是一个名为CSCalendarViewController类的实现里面,我通过调用类方便的方法创建上述的UIView并将其分配给名为_monthView一个UIView财产。

@interface CSCalendarViewController : UIViewController 

@property (weak, nonatomic) UIView *monthView;

@end


@implementation CSCalendarViewController


     __weak CSCalendarViewController *capturedSelf = self;
    // Create the current month buttons and populate with values.
    _monthView = [UIView monthViewFromDateArray:_arrayOfAllShiftsAndEvents withNibOwner:self selectedDate:_selectedDate withCompletionHandler:^(CSCalendarButton *selectedButton) {

            capturedSelf.selectedButton = selectedButton;
            [capturedSelf.selectedButton setSelected:YES];
        }

现在我的困惑是这样的。 即使我定义的属性“monthView”弱“monthView”犹抱到返回的UIView的价值。

如果我继续前进,做这样的事情:

    _monthView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)];

编译器会发出警告(因为它应该)说:“分配对象保持弱变量”。

为什么我没有得到同样的错误消息时,我给你“monthView”以从类方法返回的UIView?

我没有深刻的认识,当谈到弧前的内存管理,我想我失去了一些东西明显。 谢谢。

Answer 1:

“monthView”犹抱到返回的UIView的价值。

它不会很长。 这个问题说明了ARC的基本工作原理,以及它是如何翻译的传统保留/释放方法,而不是一个全新的内存管理系统。

ARC前

ARC之前,有没有弱或强的概念,而是指保留和分配。 分配给变量并没有什么引用计数,它是由开发人员来管理它。

现在,关于内存管理政策,方法名称以“黄金”,“新”,“复制”,或“mutableCopy”,将返回一个对象保留( 文档 )。 这意味着,在分配给一个变量,开发商并不需要明确保留(他们不得不明确地释放或自动释放):

// Will have a retain count of 1 here 
var = [NSString alloc] initWithString:@"Test"];

// Will have a retain count of 2 here 
var = [[NSString alloc] initWithString:@"Test"] retain]

// Will have a retain count of 1 here, but will be released later on automatically
var = [[NSString alloc] initWithString:@"Test"] autorelease];

// Will have a retain count of 0 here, and will be released before it reaches the variable!
var = [[NSString alloc] initWithString:@"Test"] release];

没有这样的命名方法,建议他们返回一个自动释放的对象。 开发者需要说些什么明确的,以保持对象周围长:

// Will have a retain count of 1 here, but will be released later on automatically
var = [NSString stringWithString:@"Test"];

// Will have a retain count of 1 here 
var = [[NSString alloc] initWithString:@"Test"] retain]

// Will have a retain count of 1 here, but will be released twice later on (Over-released!)
var = [[NSString alloc] initWithString:@"Test"] autorelease];

// Will have a retain count of 0 here, and will be released again later on (Over-released!)
var = [[NSString stringWithString:@"Test"] release];

ARC + MRC

ARC消除释放和保留的这种不必要的需求,而是决定如何处理基于变量将被分配到的类型的内存管理做。 这并不意味着改变了内存管理模式; 它仍然是所有保留和引擎盖下释放。 因此,如何影响你? 为了简便起见,这个答案只考虑到疲软的变量。

分配到弱变量并没有对对象的保留计数任何东西。 让我们看一个实际的例子来解释:

__weak UIView* monthView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)];

由于(在现实中,ARCness后面)此函数返回一个保留的对象,但弱变量不影响保留计数,编译器已发现的最早的点,以释放对象,以防止内存泄漏; 在配置! 因此,它会被翻译成以下,而导致错误:

UIView* monthView = [[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)] release];

现在,关于monthViewFromDateArray:这是在暗示编译器(由于其名称),这样它会返回一个自动释放的对象( 文件 )。 因为编译器知道一个autoreleased对象将在运行循环(当自动释放池被排干)被自动释放以后,它不会插入release呼叫像以前一样。 因此,分配给弱变量是不是一个问题,但它是唯一真正有效的它的使用范围之内。



Answer 2:

假设我们有方法

+(UIView*) create {
    return [[UIView alloc] init];
}

编译时,它被转换为这

+(UIView*) create {
    return [[[UIView alloc] init] autorelease];
}

现在这里:

UIView* __weak view;

//warning here
view = [[UIView alloc] init]; //1

view = [AppDelegate create];  //2

第一行被转换成这样的:

tempVar = [[UIView alloc] init];
storeWeak(tempVar, &view); //view = tempVar and marked as weak
[view release]; //view is nil after this because retain count == 0 (assignment to nil is done in release internally)

第二行:

tempVar = [MyClass create];
[tempVar retainAutoreleasedReturnValue];
storeWeak(tempVar, &view); //view = tempVar and marked as weak
[release tempVar]; //view is not nil because tempVar is autoreleased later

如果我们有这样的代码:

@autoreleasepool {
    view = [[UIView alloc] init];
    //view is nil here

    view = [AppDelegate create];
    //view equals to the return value
}
//view becomes nil here because [AppDelegate create] return value is released

您可以通过查看反汇编代码看到这一切。



文章来源: objective c class method returned value, assigned to weak/strong properties