如何使用Objective-C中的类管理内存? [英] How to manage memory using classes in Objective-C?

查看:53
本文介绍了如何使用Objective-C中的类管理内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我第一次创建iPhone应用程序,并且在内存管理方面遇到了困难,因为我以前从未处理过它.

This is my first time creating an iPhone App and I am having difficulty with the memory management because I have never had to deal with it before.

我有一个UITableViewController,并且一切正常,直到尝试在模拟器中向下滚动.崩溃说不能分配那么多内存.我将范围缩小到发生崩溃的位置:

I have a UITableViewController and it all works fine until I try to scroll down in the simulator. It crashes saying that it cannot allocate that much memory. I have narrowed it down to where the crash is occurring:

    - (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Dequeue or create a cell
    UITableViewCellStyle style =  UITableViewCellStyleDefault;
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:@"BaseCell"];
    if (!cell) cell = [[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:@"BaseCell"] autorelease];

    NSString* crayon;

    // Retrieve the crayon and its color
    if (aTableView == self.tableView)
    {
        crayon = [[[self.sectionArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] getName];
    }
    else
    {
        crayon = [FILTEREDKEYS objectAtIndex:indexPath.row];
    }

    cell.textLabel.text = crayon;

    if (![crayon hasPrefix:@"White"])
        cell.textLabel.textColor = [self.crayonColors objectForKey:crayon];
    else
        cell.textLabel.textColor = [UIColor blackColor];
    return cell;
}

这是 getName 方法:

- (NSString*)getName
{
    return name;
}

名称定义为:

@property (nonatomic, retain) NSString *name;

现在sectionArray是一个NSMutableArray,其中包含我在其中创建了 Term 的类的实例.

Now sectionArray is an NSMutableArray with instances of a class that I created Term in it.

Term 具有方法 getName ,该方法返回NSString *.问题似乎是设置蜡笔和调用 getName 的部分.我曾尝试添加 autorelease release 以及类似的其他内容,但这只会导致整个应用崩溃,甚至无法启动.

Term has a method getName that returns a NSString*. The problem seems to be the part of where crayon is being set and getName is being called. I have tried adding autorelease, release, and other stuff like that but that just causes the entire app to crash before even launching.

如果我也这样做:

cell.textLabel.text = @"test"; //crayon;

/*if (![crayon hasPrefix:@"White"])
    cell.textLabel.textColor = [self.crayonColors objectForKey:crayon];
else
    cell.textLabel.textColor = [UIColor blackColor];*/

然后我没有任何错误,一切滚动都很好.

Then I get no error whatsoever and it all scrolls just fine.

提前感谢您的帮助!

这是我尝试运行该应用程序时的完整日志,以及它崩溃时给出的错误:

Here is the full Log of when I try to run the app and the error it gives when it crashes:

[会议于2010-12-29 04:23:38 -0500开始.]

[Session started at 2010-12-29 04:23:38 -0500.]

[会议于2010-12-29 04:23:44 -0500开始.] GNU gdb 6.3.50-20050815(Apple版本gdb-967)(UTC 2009年7月14日星期二02:11:58) 版权所有2004自由软件基金会. GDB是免费软件,受GNU通用公共许可证保护,您可以 欢迎在某些条件下进行更改和/或分发. 键入显示复制"以查看条件. GDB绝对没有保修.键入显示保修"以获取详细信息. 此GDB被配置为"i386-apple-darwin".sharedlibraryapply-load-rules全部 附加到进程1429. gdb-i386-apple-darwin(1430,0x778720)malloc: * mmap(size = 1420296192)失败(错误代码= 12) 错误:无法分配区域 * *在malloc_error_break中设置一个断点以进行调试 gdb堆栈在内部错误点爬网: [0]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(align_down + 0x0)[0x1222d8] [1]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(xstrvprintf + 0x0)[0x12336c] [2]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(xmalloc + 0x28)[0x12358f] [3]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(dyld_info_read_raw_data + 0x50)[0x1659af] [4]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(dyld_info_read + 0x1bc)[0x168a58] [5]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(macosx_dyld_update + 0xbf)[0x168c9c] [6]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(macosx_solib_add + 0x36b)[0x169fcc] [7]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(macosx_child_attach + 0x478)[0x17dd11] [8]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(attach_command + 0x5d)[0x64ec5] [9]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(mi_cmd_target_attach + 0x4c)[0x15dbd] [10]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(captured_mi_execute_command + 0x16d)[0x17427] [11]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(catch_exception + 0x41)[0x7a99a] [12]/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin(mi_execute_command + 0xa9)[0x16f63] /SourceCache/gdb/gdb-967/src/gdb/utils.c:1144:内部错误:虚拟内存已耗尽:无法分配1420296192字节. 检测到GDB内部存在问题, 进一步的调试可能不可靠.

[Session started at 2010-12-29 04:23:44 -0500.] GNU gdb 6.3.50-20050815 (Apple version gdb-967) (Tue Jul 14 02:11:58 UTC 2009) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-apple-darwin".sharedlibrary apply-load-rules all Attaching to process 1429. gdb-i386-apple-darwin(1430,0x778720) malloc: * mmap(size=1420296192) failed (error code=12) error: can't allocate region ** set a breakpoint in malloc_error_break to debug gdb stack crawl at point of internal error: [ 0 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (align_down+0x0) [0x1222d8] [ 1 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (xstrvprintf+0x0) [0x12336c] [ 2 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (xmalloc+0x28) [0x12358f] [ 3 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (dyld_info_read_raw_data+0x50) [0x1659af] [ 4 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (dyld_info_read+0x1bc) [0x168a58] [ 5 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (macosx_dyld_update+0xbf) [0x168c9c] [ 6 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (macosx_solib_add+0x36b) [0x169fcc] [ 7 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (macosx_child_attach+0x478) [0x17dd11] [ 8 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (attach_command+0x5d) [0x64ec5] [ 9 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (mi_cmd_target_attach+0x4c) [0x15dbd] [ 10 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (captured_mi_execute_command+0x16d) [0x17427] [ 11 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (catch_exception+0x41) [0x7a99a] [ 12 ] /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/libexec/gdb/gdb-i386-apple-darwin (mi_execute_command+0xa9) [0x16f63] /SourceCache/gdb/gdb-967/src/gdb/utils.c:1144: internal-error: virtual memory exhausted: can't allocate 1420296192 bytes. A problem internal to GDB has been detected, further debugging may prove unreliable.

调试器以状态1退出.调试器以状态1退出.

The Debugger has exited with status 1.The Debugger has exited with status 1.


这是我为malloc_error_break设置断点时得到的回溯:


Here is the backtrace that I get when I set the breakpoint for malloc_error_break:

#0  0x0097a68c in objc_msgSend ()
#1  0x01785bef in -[UILabel setText:] ()
#2  0x000030e0 in -[TableViewController tableView:cellForRowAtIndexPath:] (self=0x421d760, _cmd=0x29cfad8, aTableView=0x4819600, indexPath=0x42190f0) at /Volumes/Main2/Enayet/TableViewController.m:99
#3  0x016cee0c in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:] ()
#4  0x016c6a43 in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:] ()
#5  0x016d954f in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow] ()
#6  0x016d08ff in -[UITableView layoutSubviews] ()
#7  0x03e672b0 in -[CALayer layoutSublayers] ()
#8  0x03e6706f in CALayerLayoutIfNeeded ()
#9  0x03e668c6 in CA::Context::commit_transaction ()
#10 0x03e6653a in CA::Transaction::commit ()
#11 0x03e6e838 in CA::Transaction::observer_callback ()
#12 0x00b00252 in __CFRunLoopDoObservers ()
#13 0x00aff65f in CFRunLoopRunSpecific ()
#14 0x00afec48 in CFRunLoopRunInMode ()
#15 0x00156615 in GSEventRunModal ()
#16 0x001566da in GSEventRun ()
#17 0x01689faf in UIApplicationMain ()
#18 0x00002398 in main (argc=1, argv=0xbfffefb0) at /Volumes/Main2/Enayet/main.m:14

--------


这是我的UITableViewController类的完整资源:

--------


Here is my complete source for the UITableViewController class:

//
//  TableViewController.m
//  Enayet
//
//  Created by Filip on 12/27/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "TableViewController.h"
#import "EnayetAppDelegate.h"

@implementation TableViewController

@synthesize crayonColors;
@synthesize filteredArray;
@synthesize sectionArray;
@synthesize searchBar;
@synthesize searchDC;

- (TableViewController*) initToCall:(NSMutableDictionary*) toUseArray
{
    self = [super initWithStyle:UITableViewStylePlain];
    crayonColors = toUseArray;
    return self;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView 
{ 
    if (aTableView == self.tableView) return 26;
    return 1; 
}

// Via Jack Lucky
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
    [self.searchBar setText:@""]; 
}

- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section
{
    if (aTableView == self.tableView) 
    {
        if ([[self.sectionArray objectAtIndex:section] count] == 0)
            return nil;
        //return [NSString stringWithFormat:@"%@", [[ALPHA substringFromIndex:section] substringToIndex:1]];
        return [[ALPHA substringFromIndex:section] substringToIndex:1];
    }
    else return nil;
}

- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section 
{
    // Normal table
    if (aTableView == self.tableView) return [[self.sectionArray objectAtIndex:section] count];

    // Search table
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", self.searchBar.text];
    self.filteredArray = [self.crayonColors.allKeys filteredArrayUsingPredicate:predicate];
    return self.filteredArray.count;
}

// Convert a 6-character hex color to a UIColor object
- (UIColor *) getColor: (NSString *) hexColor
{
    unsigned int red, green, blue;
    NSRange range;
    range.length = 2;

    range.location = 0; 
    [[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&red];
    range.location = 2; 
    [[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&green];
    range.location = 4; 
    [[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&blue];   

    return [UIColor colorWithRed:(float)(red/255.0f) green:(float)(green/255.0f) blue:(float)(blue/255.0f) alpha:1.0f];
}

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Dequeue or create a cell
    UITableViewCellStyle style =  UITableViewCellStyleDefault;
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:@"BaseCell"];
    if (!cell) cell = [[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:@"BaseCell"] autorelease];

    NSString* crayon;

    // Retrieve the crayon and its color
    if (aTableView == self.tableView)
    {
        Term *term = (Term *) [[self.sectionArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
        crayon = [term name];
    }
    else
    {
        crayon = [FILTEREDKEYS objectAtIndex:indexPath.row];
    }

    cell.textLabel.text = crayon;

    if (![crayon hasPrefix:@"White"])
        cell.textLabel.textColor = [self.crayonColors objectForKey:crayon];
    else
        cell.textLabel.textColor = [UIColor blackColor];
    return cell;
}

// Grouped Tables do not support section indices (even though they kind of do)

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)aTableView 
{
    if (aTableView == self.tableView)  // regular table
    {
        NSMutableArray *indices = [NSMutableArray arrayWithObject:UITableViewIndexSearch];
        for (int i = 0; i < 26; i++) 
            if ([[self.sectionArray objectAtIndex:i] count])
                [indices addObject:[[ALPHA substringFromIndex:i] substringToIndex:1]];
        // [indices addObject:@"\ue057"]; // <-- using emoji
        return indices;
    }
    else return nil; // search table
}


- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    if (title == UITableViewIndexSearch) return 0;
    return [ALPHA rangeOfString:title].location;
 }

- (void)goToTwo:(Term*) toGive
{
    EnayetAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    [appDelegate setTerm:toGive];
    [appDelegate displayView:2];
}

// Respond to user selections by updating tint colors
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if (aTableView == self.tableView)
    {
        [self goToTwo:[[self.sectionArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]];
    }
}

- (void) viewDidLoad
{
    // Prepare the crayon color dictionary
    NSString *pathname = [[NSBundle mainBundle]  pathForResource:@"crayons" ofType:@"txt" inDirectory:@"/"];
    NSArray *rawCrayons = [[NSString stringWithContentsOfFile:pathname encoding:NSUTF8StringEncoding error:nil] componentsSeparatedByString:@"\n"];
    self.crayonColors = [NSMutableDictionary dictionary];

    self.sectionArray = [NSMutableArray array];
    for (int i = 0; i < 26; i++) [self.sectionArray addObject:[NSMutableArray array]];
    for (NSString *string in rawCrayons) 
    {
        [self.crayonColors setObject:CRAYON_COLOR(string) forKey:CRAYON_NAME(string)];
        NSUInteger firstLetter = [ALPHA rangeOfString:[string substringToIndex:1]].location;
        if (firstLetter != NSNotFound) [[self.sectionArray objectAtIndex:firstLetter] addObject:[[Term alloc] initToCall:CRAYON_NAME(string)]];
    }
    //NSLog(@"%@", sectionArray);

    // Create a search bar
    self.searchBar = [[[UISearchBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)] autorelease];
    self.searchBar.tintColor = COOKBOOK_PURPLE_COLOR;
    self.searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
    self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
    self.searchBar.keyboardType = UIKeyboardTypeAlphabet;
    self.tableView.tableHeaderView = self.searchBar;

    // Create the search display controller
    self.searchDC = [[[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self] autorelease];
    self.searchDC.searchResultsDataSource = self;
    self.searchDC.searchResultsDelegate = self;
}
@end

------


这是我的Term.m文件:

------


Here is my Term.m file:

//
//  Term.m
//  Enayet
//
//  Created by Filip on 12/27/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "Term.h"


@implementation Term

@synthesize name;

- (Term*)initToCall:(NSString*) toSetName
{
    name = toSetName;
    return self;
}

- (NSString*)getName
{
    return name;
}

-(void)dealloc
{
    [name release];
    [super dealloc];
}

@end

推荐答案

在您的initToCall:方法中,替换:

name = toSetName;

具有:

name = [toSetName retain];

即使您将该属性设置为保留"属性,也不会保留原始值,因为您直接对其进行了分配.用可可术语来说,您永远不会拥有"它.由于您传入的字符串值不归您所有,因此最终它消失了,这就是您看到崩溃的原因.如果直接在init方法中分配ivars,则必须记住自己保留或复制它们.您的另一个选择是使用访问器:

Even tho you set the property as a "retain" property, your original value is not retained because you assign it directly. In Cocoa terms, you never "take ownership" of it. Since the string value you were passed in is not owned by you, it ends up going away on you, and that is why you see the crash. If you assign ivars directly in the init methods, you have to remember to retain or copy them yourself. Your other option is to use the accessors:

self.name = toSetName;

在这种情况下,您将自动调用综合的setter,它将为您保留该属性(因为您将其指定为"retain"属性).

In that case, you will automatically invoke your synthesized setter, which will retain the property for you (since you specified it as a "retain" property).

另外,尽管这里与您的问题没有直接关系,但始终从您自己的指定初始值设定项调用超类的指定初始值设定项是一种好方法.因此,通常的模式是:

Also, while not directly related to your issue here, it's good form to always invoke your superclass's designated initializer from your own designated initializer. So, the general pattern would be:

- (id)initToCall:(NSString*)toSetName
{
  if( (self = [super init]) ) { // call NSObject's designated initializer
    // do our initialization
    name = [toSetName retain]; // take ownership of this string
  }
  return self;
}

这篇关于如何使用Objective-C中的类管理内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆