objective c class方法返回值,赋值为weak / strong属性

时间:2012-12-05 18:06:24

标签: iphone objective-c cocoa-touch ios6 xcode4.5

我面临着一些涉及弱势和强势属性的混乱。为简洁起见,我不会包含整个代码。

我创建了一个类方便方法,它返回一个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的任何内容。

现在在'owner'的实现中,这是一个名为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时,为什么我没有收到相同的错误消息?

对于ARC之前的内存管理,我没有深刻的理解,我认为我遗漏了一些明显的东西。感谢。

2 个答案:

答案 0 :(得分:2)

  

'monthView'仍然保留返回的UIView的值。

不会很久。这个问题演示了ARC的基本工作原理,以及它如何转换为传统的保留/释放方法,而不是一个全新的内存管理系统。

前ARC

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

现在,关于内存管理策略,名称以“alloc”,“new”,“copy”或“mutableCopy”开头的方法将返回一个保留对象(Documentation)。这意味着,在分配给变量时,开发人员不需要明确保留(他们必须明确释放或自动释放):

// 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:,这是建议编译器(由于其名称),它将返回一个自动释放的对象(Documentation)。因为编译器知道自动释放的对象将在稍后的运行循环中自动释放(当自动释放池耗尽时),它不会像以前一样插入release调用。因此,对弱变量的赋值不是问题,但它只在它所使用的范围内真正有效。

答案 1 :(得分:1)

说我们有方法

+(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

您可以通过查看代码反汇编来查看所有这些内容。