我已经编程了几个月的Objective-C并且到目前为止做得很好而不必发布任何问题。这将是我的第一次。问题是我在其中一个方法中从数据对象收到内存泄漏警告。我可以看到问题是我在不释放它的情况下向它发送一个alloc,但是我不知道如何让它在内存中保留对象。如果我取出分配,程序崩溃。如果我留下它,它会泄漏记忆。这是有问题的方法:
+ (id) featureWithID:(int)fID name:(NSString*)fName secure:(int)fSecure {
Feature *newFeature = [[self alloc] init];
newFeature.featureID = fID;
newFeature.featureName = fName;
newFeature.featureSecure = fSecure;
return [newFeature autorelease];
}
此方法由我的视图控制器中的另一个方法调用。这种方法如下:
+ (NSMutableArray*) createFeatureArray {
NSString *sqlString = @"select id, name, secure from features";
NSString *file = [[NSBundle mainBundle] pathForResource:@"productname" ofType:@"db"];
sqlite3 *database = NULL;
NSMutableArray *returnArray = [NSMutableArray array];
if(sqlite3_open([file UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = [sqlString UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
Feature *myFeature = [Feature featureWithID:sqlite3_column_int(compiledStatement,0)
name:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)]
secure:sqlite3_column_int(compiledStatement,2)];
[returnArray addObject:myFeature];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return returnArray;
}
我尝试了几个方法,比如创建一个featureWithFeature类方法,这个方法允许我在调用方法中为init分配功能,但这也会使程序崩溃。
如果您需要任何澄清或代码的任何其他部分,请告知我们。提前感谢您的帮助。
更新:2011年4月14日
在阅读前两个回复后,我实施了该建议,发现该程序现在崩溃了。关于如何追查罪魁祸首我完全不知所措。希望这有帮助,我也从视图控制器发布调用方法:
- (void)setUpNavigationButtons {
// get array of features from feature data controller object
NSArray *featureArray = [FeatureController createFeatureArray];
int i = 0;
for (i = 0; i < [featureArray count]; i++) {
Feature *myFeature = [featureArray objectAtIndex:i];
CGRect buttonRect = [self makeFeatureButtonFrame:[featureArray count] withMember:i];
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setFrame:buttonRect];
[aButton addTarget:self action:@selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
[aButton setTitle:[NSString stringWithFormat:@"%@",myFeature.featureName] forState:UIControlStateNormal];
aButton.tag = myFeature.featureID;
[self.view addSubview:aButton];
}
}
注意:这些方法的发布方式与它们被调用的顺序相反。最后一个方法调用第二个方法,然后调用第一个方法。
更新:我已经更新了这些函数来显示现在的内容:下面,我将发布该对象的头文件 - 也许这会有所帮助
@interface Feature : NSObject {
int featureID;
int featureSecure;
NSString *featureName;
}
@property (nonatomic, assign) int featureID;
@property (nonatomic, assign) int featureSecure;
@property (nonatomic, retain) NSString *featureName;
- (id) init;
- (void) dealloc;
+ (id) featureWithID:(int)fID name:(NSString*)fName secure:(int)fSecure;
@end
@interface FeatureController : NSObject {
}
- (id) init;
- (void) dealloc;
+ (NSMutableArray*) createFeatureArray;
+ (Feature*) getFeatureWithID:(int)fetchID;
@end
答案 0 :(得分:1)
便捷方法应遵循返回自动释放对象的惯例。改变这个:
+ (id) featureWithID:(int)fID name:(NSString*)fName secure:(int)fSecure {
Feature *newFeature = [[self alloc] init];
...
return newFeature;
}
为:
+ (id) featureWithID:(int)fID name:(NSString*)fName secure:(int)fSecure {
Feature *newFeature = [[self alloc] init];
...
return [newFeature autorelease];
}
答案 1 :(得分:1)
方法的名称 - +featureWithID:name:secure:
- 表示它返回调用者不拥有的对象。相反,它返回一个已保留的对象,调用者因此拥有并必须释放。要解决此问题(以及您的泄漏),只需将return newFeature
替换为return [newFeature autorelease]
。
您不需要做任何事情,因为您自己的代码不需要持久的所有权声明,而您添加对象的数组将通过它来管理自己的所有权声明。
答案 2 :(得分:0)
在+createFeatureArray
中,你过度释放了数组:
+ (NSMutableArray*) createFeatureArray {
…
NSMutableArray *returnArray = [[[NSMutableArray alloc] init] autorelease];
…
return [returnArray autorelease];
}
在第一行中,您使用了+alloc
,因此您拥有该数组。然后你使用了-autorelease
,所以你不再拥有这个数组了。这意味着您不应向-release
行发送-autorelease
或return
。
您可以通过将这些行更改为:
来解决此问题+ (NSMutableArray*) createFeatureArray {
…
NSMutableArray *returnArray = [NSMutableArray array];
…
return returnArray;
}
此外,除非调用者认为数组是可变的,否则应该更改该方法以返回NSArray
而不是NSMutableArray
。您可以按原样保留代码,即返回一个可变数组,即使方法声明声明返回类型为NSArray
。
<小时/> 至于您的便利构造函数,根据您是要返回自有对象还是非自有对象,基本上有两种选择:
如果要返回拥有的对象,请使用+alloc
或+new
进行分配,并在不自动释放的情况下将其返回。您的方法名称应包含new
,例如+newFeatureWithId:…
如果要返回一个不属于调用者的对象,请使用+alloc
或new
进行分配,并在将其返回给调用者之前/之后自动释放它。您的方法名称不应包含new
,alloc
或copy
。
<小时/> 在
-setUpNavigationButtons
中,您通过+createFeatureArray
获取非拥有数组,根据它分配可变数组,并释放可变数组,而无需添加或删除元素。当您需要添加/删除元素时,可变数组是有意义的。如果您没有此需求,可以将方法更改为:
- (void)setUpNavigationButtons {
// get array of features from feature data controller object
NSArray *featureArray = [FeatureController createFeatureArray];
…
// [featureArray release];
您删除了[featureArray release]
,因为您在该方法中没有featureArray
。
修改:在-setUpNavigationButtons
中,您将保留您创建的按钮,并在发布后立即保留。在那个特定的方法中,那些是幂等操作 - 它们本身并没有错,但根本不是必需的。您可以用
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
…
[self.view addSubview:aButton];
// [aButton release];
即,不要保留它,也不要释放它。