Iphone 目标c类方法返回值,分配给弱/强属性

Iphone 目标c类方法返回值,分配给弱/强属性,iphone,objective-c,cocoa-touch,ios6,xcode4.5,Iphone,Objective C,Cocoa Touch,Ios6,Xcode4.5,我面临着一点关于弱属性和强属性的困惑。为了简洁起见,我不会包含整个代码 我创建了一个返回UIView对象的类便利方法,并在UIView类别中实现它,作为子类化的替代方法 @implementation UIView (CSMonthView) + (UIView *)monthViewFromDateArray:(NSArray *)arrayOfAllShiftsAndEvents withNibOwner:(id)owner selectedDate:(NSDate *)selec

我面临着一点关于弱属性和强属性的困惑。为了简洁起见,我不会包含整个代码

我创建了一个返回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

@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];
        }
现在,在“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)];
@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
编译器给出一个警告(正如它应该的那样)说“将保留对象分配给弱变量”

为什么在将“monthView”分配给从类方法返回的UIView时,没有收到相同的错误消息

我对弧前内存管理没有深入的了解,我想我遗漏了一些明显的东西。谢谢

“monthView”仍然保留返回的UIView的值

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

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

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

没有这种命名约定的方法建议它们返回一个自动释放的对象。开发人员需要明确地说些什么,以使对象保持更长的时间:

// 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)];
因为(实际上,在弧的后面)这是返回一个保留的对象,但是弱变量不会影响保留计数,编译器已经找到了释放对象的最早点,以防止内存泄漏;分配!因此,它将转换为以下内容,并导致错误:

UIView* monthView = [[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)] release];
现在,关于
monthViewFromDateArray:
,这向编译器建议(由于其名称),它将返回一个自动删除的对象()。因为编译器知道自动释放的对象稍后会在运行循环中自动释放(当自动释放池耗尽时),所以它不会像以前那样插入
release
调用。因此,弱变量的赋值不是问题,但它只在其使用的范围内有效。

假设我们有方法

+(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
如果我们有这样的代码:

    _monthView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 200.0)];
@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

通过查看代码反汇编,您可以看到所有这些。

我测试并确认了您的说法,即monthView不会长时间指向UIView对象。我在ViewDidDisplay中放置了一个NSLog,果然显示为零。MonthView的值为非nil,直到它离开ViewWillDisplay的范围+1如果我能够的话。这就消除了编译器在后台所做工作的魔力,并解释了为什么我认为我看到的结果不一致。谢谢