【问题标题】:When should I release my array?我应该什么时候释放我的阵列?
【发布时间】:2011-06-24 02:03:17
【问题描述】:

我正在解析来自 Internet 的一些 JSON,然后将它们添加到一个数组中,该数组是我的 UITableView 的数据源。我不确定什么时候应该释放我的数组?

.h:项目

@property(nonatomic,retain)NSMutableArray*  items;

.m:connectionDidFinishLoading

// fetch succeeded    
    NSString* json_string = [[NSString alloc] initWithData:retrievedData encoding:NSUTF8StringEncoding];

    //Check ST status
    int status =  [[[[json_string objectFromJSONString] valueForKey:@"response"] valueForKey:@"status"]intValue];
    //NSLog(@"Status: %d", status);

    items = [[NSMutableArray alloc] init];
    NSDictionary* messages = [[NSDictionary alloc] init]; 

    switch (status) {
        case 200:
            messages = [[[json_string objectFromJSONString] valueForKey:@"messages"] valueForKey:@"message"];

            for (NSDictionary *message in messages)
            {
                [items addObject:message];
            }
            [self.tableView reloadData];
        break;

        default:
        break;
    }

【问题讨论】:

  • "我应该什么时候释放我的 X?" - 尽早! ;)
  • 你能发布更完整的代码吗?正如所写,这不起作用(或编译)
  • 更新了更完整的代码

标签: iphone objective-c cocoa-touch memory nsarray


【解决方案1】:

第一,如果您打算在其上调用addObject:,您可能希望将items 声明为NSMutableArray 的实例。

第二,将它声明为一个属性,这样如果你最终多次获得它,旧值将在你这样做时被释放。

self.items = [NSMutableArray array];

正确的发布点是dealloc

【讨论】:

    【解决方案2】:

    如果您满足以下条件,您可能不想立即发布它:

    • 使用 didSelectRowAtIndexPath: 方法获取详细视图并将此数据传递给它们
    • 在 cellForRowAtIndexPath: 方法中定义自定义 UITableViewCell 样式
    • 在别处使用此数据

    最佳实践是声明一个实例变量并在.m中合成它,在适当的操作中使用并在dealloc方法中释放。

    您可以使用的一个可能的发布点是您刷新表格上显示的数据的位置。

    示例:

    我从我的应用程序中的 API 获取数组中的字典并使用类似的东西。

    MyTableViewController.h

    @interface MyTableViewController {
        NSMutableArray *items;
    }
    
    @property (nonatomic, retain) NSMutableArray *items;
    
    @end
    

    MyTableViewController.m

    @implementation MyTableViewController
    
    @synthesize items;
    
    - (void)dealloc
    {
        [items release];
        [super dealloc];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return [items count];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        static NSString *cellIdentifier = @"FilesCellIdentifier";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
        if (cell == nil) {
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
        }
    
        cell.textLabel.text = [[items objectAtIndex:indexPath.row] valueForKey:@"name"];
        cell.imageView.image = [UIImage imageNamed:[[NSString alloc] initWithFormat:@"filetype_%@.png", [[items objectAtIndex:indexPath.row] valueForKey:@"type"]]];
    
        return cell;
    }
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
            MyDetailViewController *detailViewController = [[MyDetailViewController alloc] initWithNibName:@"MyDetailViewController" bundle:[NSBundle mainBundle]];
            detailViewController.item = [items objectAtIndex:indexPath.row];
            [self.navigationController pushViewController:detailViewController animated:YES];
            [detailViewController release];
            detailViewController = nil;
        }
    }
    
    - (void)getItems
    {
        [items release];
        items = [[NSMutableArray alloc] init];
    
        //Do some requests here
    
        for (NSDictionary *dict in results)
        {
            [items insertObject:dict atIndex:0];
        }
    
        [self.tableView reloadData];
        [self stopLoading];
    }
    
    @end
    

    【讨论】:

      【解决方案3】:

      在错误的地方释放有时会导致内存泄漏,在分配本身之前,您可能会遇到 if() { [...release]} 之类的条件。未经测试,但这种释放可以避免泄漏。

      【讨论】:

        【解决方案4】:

        最常见的是将 items 变量作为类的属性,一旦您可能需要在 tableView:cellForRowAtIndexPath: 方法中使用它。

        因此,将其作为属性变量,您可以在 dealloc 方法上释放它。

        【讨论】:

          【解决方案5】:

          很明显,UITableView 将使用您的数组 item 来显示数据。

          首先将其声明为 .h 类中的实例变量。

          .h 类

          @interface MyClass 
          {
            MSMutableArray* items;
          }
          @property(nonatomic,retain) MSMutableArray* items;
          
          @end
          

          在您的 .m 类中。

          @synthesis iMyArray;
          

          你填充数组的代码应该是

          NSMutabelArray* itemsTemp = [[NSMutabelArray alloc] initWithCapacity:1];
          
          messages = [[[json_string objectFromJSONString] valueForKey:@"messages"] valueForKey:@"message"];
          [json_string release];
          
          for (NSDictionary *message in messages) {
              NSLog(@"%@",[message valueForKey:@"body"]);
              [itemsTemp addObject:message];
          }
          
          
          self.items= itemsTemp;
          
          [itemsTemp release];
          itemsTemp = nil;
          
          [self.tableView reloadData];
          

          现在在dealloc 中释放你的数组实例。

          -(void) dealloc
          {
             if(items )
             {
              [items release];
              items = nil ;
             }
             [super dealloc];
          }
          

          【讨论】:

          • @Sheehan Alam:您尝试使用我的答案了吗?
          • 你不需要dealloc中的if语句
          【解决方案6】:

          正确的方法是在 .h 类中将其设为属性,因为您已将其声明为属性:记住一件事始终使用 self 分配属性。

          您的声明items=[[NSMutableArray alloc] init];

          是错误的。(使用 self)也因为你的属性是 retain 类型的 using alloc 增加保留计数。这给你一个泄漏。

          所以在viewDidLoad中这样使用

          NSMutableArray *tempArray=[[NSMutableArray alloc] init];
          self.items=tempArray;
          [tempArray release];
          

          然后在 dealloc 中释放您的 items 数组,并在 viewDidUnload 中将其设置为零

          - (void)viewDidUnload {
              [super viewDidUnload];
              self.items=nil;
          }
          
          - (void)dealloc {
              [self.items release];
          [super dealloc];
          }
          

          希望您现在可以理解应该如何使用它。

          【讨论】:

          • 我要补充的是,您不应该使用 setter 发布,而是直接使用 ivar。 - (void)dealloc { [items release]; [super dealloc]; }
          • 实际上,通过不使用 retain 设置器,将 ivar 直接分配给 alloc/init 非常好。在任何一种情况下,都有一个 +1 保留计数,并且您可以获得额外的好处,即不必将另一个对象转储到新兴的自动释放池中。此外,霍尔格提出了一个很好的观点。这主要是传统和风格,但没有必要打破有效的东西。
          【解决方案7】:

          根据苹果的documentation of UITableView reloadData method

          “[...] 为了提高效率,表格视图只重新显示那些可见的行”

          这意味着只要表正在使用,就不应该释放 items 数组,即您必须将数组声明为属性。

          首先因为如果您滚动视图,您仍然需要items 信息来显示下方或上方的行。

          其次,因为作为一个属性,如果您碰巧为 items 分配了一个新值,您可以确保之前的值将被释放。

          最后,释放属性的常见位置是在dealloc 方法中,具体取决于您在viewDidUnload 方法中的实现。

          【讨论】:

            猜你喜欢
            • 2018-11-10
            • 1970-01-01
            • 1970-01-01
            • 2011-08-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-12
            相关资源
            最近更新 更多