【问题标题】:objective-c: alloc vs synthesise/retain目标-c:分配与综合/保留
【发布时间】:2011-04-27 12:25:05
【问题描述】:

我有一个初学者的问题。我想在我的代码的所有部分(而不是单个方法/函数)中访问 UIView。

因此我在@interface 部分声明了它

UIView *calendarView;

然后是@property (nonatomic, retain) UIView *calendarView。在@implementation 我有@synthesise calendarView

现在我想定义这个视图的框架并编码如下:

    CGRect calendarFrame = CGRectMake(170,     8, 200, 50);
calendarView = [[UIView alloc] initWithFrame:calendarFrame];

但是我现在想知道我是否在这里做错了什么,因为 calendarView 已经被保留和合成。 UIView alloc 肯定是多余的,甚至必然会使应用程序崩溃,因为我遇到了内存问题,对吧?

所以我虽然应该编写此代码而不是前两行代码,但它只会产生根本不显示 calendarView 的效果:

[calendarView setFrame:CGRectMake(170, 8, 200, 50)];

所以我的问题是我是否真的需要先分配视图才能使用它?还是有其他解决方案?

【问题讨论】:

  • 第一个问题:你的calenderView是怎么创建的?来自 XIB?

标签: ios objective-c cocoa-touch alloc


【解决方案1】:

只有在内存中拥有一个对象后才能保留它(即你已经分配了它)..所以下面给出的代码是正确且需要的..

CGRect calendarFrame = CGRectMake(170,     8, 200, 50);
calendarView = [[UIView alloc] initWithFrame:calendarFrame];//you have alloc'ed once

现在您将此视图添加到父视图。例如,我在 UIViewController 实现中..

[self.view addSubView:calendarView];  //now only your retain takes place. //So now calenderView has to release twice..Once by you (since you alloced it) and once by viewcontroller (since it has retained it)...
[calendarView release];//we are releasing once but the object will not be removed from memory since it is retained by viewController..Our part in memory management is over..Now when this viewController get dealloced it releases 

你可以在这个 UIViewController 的整个实现中使用这个 calendarView。

-(void)dealloc{
 [super dealloc];//should be last in dealloc..Now the entire controller will be dealloced along with the calenderView which is retained by viewController and the memory will be freed for future uses..
}

这些是一些有用的教程..比苹果的文档更容易理解..但也阅读苹果的文档..

http://ferasferas.wordpress.com/2010/12/05/introduction-to-memory-management-on-iphone/

http://iosdevelopertips.com/objective-c/memory-management.html

http://mauvilasoftware.com/iphone_software_development/2008/01/iphone-memory-management-a-bri.html

https://humblecoder.blogspot.com/2009/08/iphone-tutorial-memory-management.html

【讨论】:

    【解决方案2】:

    合成一个属性实际上并不为您实例化一个对象。你仍然需要你的 alloc 和 init 方法。

    在上面的代码中,如果您想使用该属性,您应该使用self.calendarView 而不仅仅是calendarView。 (执行后者是绕过属性并直接使用实例变量,这通常不是您想要的,除了您的 dealloc 方法中的可能例外。)

    您应该进行的最后一项更改:假设您的属性被标记为保留,它将处理将您的对象保持在自身周围。因此,您应该自动释放要放入其中的对象。试试这个:

    self.calendarView = [[[UIView alloc] initWithFrame:calendarFrame] autorelease];
    

    【讨论】:

    • 谢谢。但是我还是不明白为什么要在calendarView前面使用'self'。如果不使用它,一切似乎都可以正常工作,那么我为什么要使用它呢?会不会有什么严重的后果?
    • 如果你不使用它,你正在访问你直接创建的实例变量。如果您确实使用它,您将通过该属性。为什么有区别?首先,当你给它赋值时,该属性会执行retain,但实例变量不会。这具有内存管理的含义。其次,使用该属性使您能够在以后更改其行为。假设你有一个 NSString 属性。稍后,您可能会决定希望该字符串始终为小写。创建一个名为 setString: 的方法,每当您使用该属性时都会调用它。
    【解决方案3】:

    除了可能的内存泄漏之外,您在第一个示例中实际上没有做错任何事情。您只是错误地认为您的 calendarView 已被保留,因为这是您定义属性的方式,这是不正确的。将属性定义为仅保留意味着当您调用self.calendarView = someotherview 时,someotherview 将被保留,calendarView 中的旧值将被释放,然后 calendarView 将设置为someotherview。在没有 self 的情况下使用 calendarView 不会为您提供任何内存管理规则,例如属性,这就是您的第一个示例可以使用的原因。您可能希望您的代码看起来更像这样。

    CGRect calendarFrame = CGRectMake(170,     8, 200, 50);
    self.calendarView = [[[UIView alloc] initWithFrame:calendarFrame] autorelease];
    

    【讨论】:

      【解决方案4】:

      是的,

      在使用 UIView 之前,您需要分配或从其他来源获取它(在 dealloc 中释放它,因为您保留它)。

      在下面使用

         CGRect calendarFrame = CGRectMake(170,     8, 200, 50);
      self.calendarView = [[[UIView alloc] initWithFrame:calendarFrame] autorelease];
      

      阅读苹果文档以了解内存管理..

      http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

      【讨论】:

        【解决方案5】:

        因此我在@interface 部分声明了它

        对,这只是保留空间和标签来访问具有类型+名称的 ivar

        然后@property(非原子,保留)UIView *calendarView。

        是的,它声明了访问器(setter+getter),以及合成后的操作

        在@implementation 我有@synthesise calendarView。

        定义(实现)由属性声明声明的访问器。

        现在我想定义这个视图的框架并编码如下:

        ... 但是我现在想知道我是否在这里做错了什么,因为 calendarView 已经被保留和合成。 UIView alloc 肯定是多余的,甚至必然会使应用程序崩溃,因为我遇到了内存问题,对吧?

        首先,您的内存管理已关闭:

        CGRect calendarFrame = CGRectMake(170,     8, 200, 50);
        UIView * view = [[UIView alloc] initWithFrame:calendarFrame];
        self.calendarView = view; // use the setter, unless in init... or dealloc
        [view release], view = 0;
        

        两个: 您通常不会在创建 UIView 时有太多用处。通常,您将创建它的子类。

        三个(回答您的问题): 这没有什么问题。变量将是nil,直到它被设置。对于声明的类型,该字段不是默认初始化的——嗯,确实如此,但该类型实际上是一个指针,所以结果是它被初始化为 nil。您可以创建一个视图或从其他地方传递它。在此之前,视图将为 nil/NULL/0。

        所以我虽然应该编写此代码而不是前两行代码,但它只会产生根本不显示 calendarView 的效果:

        [calendarView setFrame:CGRectMake(170, 8, 200, 50)]; 所以我的问题是我是否真的需要先分配视图才能使用它?还是有其他解决方案?

        更详细地回到第 2 点:在大多数情况下,您需要创建一个子类。 UIView/NSView 默认不绘制,但可以作为视图容器使用。因此,您可能需要从一些现有的子类开始熟悉系统提供的视图。

        一旦你掌握了它,尝试实现你自己的子类并覆盖drawRect:

        许多初学者都喜欢使用 Interface Builder(现已集成到 Xc4 中)——一个所见即所得的视图编辑器。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-05-29
          • 1970-01-01
          • 1970-01-01
          • 2010-11-25
          • 1970-01-01
          • 2012-06-21
          • 2012-09-22
          • 1970-01-01
          相关资源
          最近更新 更多