我正在研究内存管理,我已经制作了一个管理表对象的小程序。
这是我的.h:
@interface Person : NSObject {
NSString *firstName;
NSString *lastName;
}
@property (readwrite, copy) NSString *firstName;
@property (readwrite, copy) NSString *lastName;
这是我的.m:
- (IBAction)clic2:(id)sender {
Person *pers = [[Person alloc]init];
NSMutableArray *myarray = [[NSMutableArray alloc] init];
[pers setFirstName:@"FN 1"]; // = pers.firstName
[pers setLastName:@"LN 1"]; // = pers.lastName
[myarray addObject:pers];
[pers setFirstName:@"FN 2"];
[pers setLastName:@"LN 2"];
[myarray addObject:pers];
[pers release];
for(int i = 0; i < [myarray count]; i++)
{
pers = [myarray objectAtIndex:i];
NSLog(@"%d %@ %@ %@", [myarray objectAtIndex:i], pers, pers.firstName, pers.lastName);
}
}
- (void)dealloc
{
[firstName release];
firstName = nil;
[lastName release];
lastName = nil;
[super dealloc];
}
这是我的NSLog
2011-04-28 21:40:11.568 temp[4456:903] 4495296 <Person: 0x1004497c0> FN 2 LN 2 2011-04-28 21:40:11.571 temp[4456:903] 4495296 <Person: 0x1004497c0> FN 2 LN 2
如您所见,存储的信息是相同的;这似乎是因为myarray
总是在数组中存储相同的内存地址/内容。
我从中了解到,当我在第二次通话时更改pers
的内容时,系统也会更改myarray
中的信息。
我该怎么做才能不覆盖数据?
感谢您的回答。
编辑:这个例子适用于2个人,但想法是管理一个无限的数字
EDIT2:感谢所有内存管理解释
答案 0 :(得分:3)
您只创建一个人的实例并多次修改它(覆盖过程中的值)。将对象添加到数组不会创建它的副本。它只维护对数组中该对象的引用。
以下是您的代码可以执行的操作示例 -
NSMutableArray *myarray = [[NSMutableArray alloc] init];
Person *pers1 = [[Person alloc]init];
[pers1 setFirstName:@"FN 1"]; // = pers1.firstName
[pers1 setLastName:@"LN 1"]; // = pers1.lastName
[myarray addObject:pers1];
[pers1 release];
Person *pers2 = [[Person alloc]init];
[pers2 setFirstName:@"FN 2"];
[pers2 setLastName:@"LN 2"];
[myarray addObject:pers2];
[pers2 release];
答案 1 :(得分:3)
数组不会复制添加到它的对象,它只是保留它们。对于-clic2:
方法的范围,您只有一个Person对象。您设置数据并将其添加到阵列。该数组存储指向Person对象的指针并增加其保留计数。但是您仍然只有一个Person对象,因此对名字或姓氏的任何更改都将覆盖您设置的原始数据。你在-clic2:
方法结束时在数组中得到的是对同一个Person对象的两个引用。
你想要的是这样的:
- ( IBAction )buttonClicked: (id)sender
{
Person *person;
NSMutableArray *array;
NSInteger i, count = 10;
array = [[ NSMutableArray alloc ] initWithCapacity: count ];
for ( i = 1; i <= count; i++ ) {
/* create a new Person object on each iteration through the loop */
person = [[ Person alloc ] init ];
/* person has a -retainCount of at least +1 after allocation */
person.firstName = [ NSString stringWithFormat: @"FN %d", i ];
person.lastName = [ NSString stringWithFormat: @"LN %d", i ];
/* adding the object increments the person retainCount to at least +2 */
[ array addObject: person ];
/*
* -release decrements the retainCount, so when we release the array
* at the end of the method and it sends release to all its objects
* the memory allocated for the Person objects will be reclaimed.
*/
[ person release ];
}
for ( person in array ) {
NSLog( @"%@ %@ %@", person, person.firstName, person.lastName );
}
/* releasing the array also sends -release to all its objects */
[ array release ];
}
答案 2 :(得分:2)
在您的代码中
[pers setFirstName:@"FN 1"]; // = pers.firstName
[pers setLastName:@"LN 1"]; // = pers.lastName
[myarray addObject:pers];
[pers setFirstName:@"FN 2"];
[pers setLastName:@"LN 2"];
[myarray addObject:pers];
您正在向数组中添加两次相同的对象,当您pers
和setFirstName:
第二次执行时,数组会存储指向Person对象setLastName
的指针内存中的同一个对象,你的指针是一样的。当你调用addObject时:它只是增加该对象的保留计数并存储它的指针,它不会创建它的副本。
创建名为pers2的第二个Person对象并执行以下操作。
[pers1 setFirstName:@"FN 1"]; // = pers.firstName
[pers1 setLastName:@"LN 1"]; // = pers.lastName
[myarray addObject:pers1];
[pers2 setFirstName:@"FN 2"];
[pers2 setLastName:@"LN 2"];
[myarray addObject:pers2];
当你完成时,也不要忘记释放myarray,目前你正在泄漏那个物体。
另外请注意,您应该使用快速枚举来遍历数组。
for(Person *person in myarray) {
// your code
}
答案 3 :(得分:2)
这种情况正在发生,因为您只有一个Person
对象。
执行此操作时:
Person *pers = [[Person alloc] init];
pers
指向一个包含Person
对象的内存块;它包含一个位置或地址。它是“指向人的指针”。当你这样做时:
[myarray addObject:pers];
数组不会复制任何内存块;它只是复制由pers
指示的位置。*更改pers
变量的值时,它会更改同一块中的内存。您仍然在同一位置有一个Person
对象,但内容不同。将pers
再次添加到数组时:
[myarray addObject:pers]; // Second time
数组只生成指针的另一个副本,它仍然只有相同的位置,因此数组有两个指针副本;两个相同的地址。因此,当您查看这些地址的值时,您会看到相同的值,因为它实际上只是一个对象。
*它还表明它有兴趣通过在该位置的对象上调用retain
来保持该内存。
答案 4 :(得分:1)
如果真的想要复制最好的东西,你可以做的是让Person类实现NSCopying协议。
在.h中添加NSCopying声明,其余部分保持不变
@interface Person : NSObject <NSCopying> {
...
}
.m(与以前相同,但附加此方法)
- (id)copyWithZone:(NSZone *)zone {
Person *objectCopy = [[Person allocWithZone:zone] init];
objectCopy.firstName = self.firstName;
objectCopy.lastName = self.lastName;
return [objectCopy autorelease];
}
然后你可以这样做:
Person *pers = [[Person alloc]init];
NSMutableArray *myarray = [[NSMutableArray alloc] init];
[pers setFirstName:@"FN 1"]; // = pers.firstName
[pers setLastName:@"LN 1"]; // = pers.lastName
[myarray addObject:[pers copy]];
[pers setFirstName:@"FN 2"];
[pers setLastName:@"LN 2"];
[myarray addObject:[pers copy]];
[pers release];