1

所以这是我的场景——在我做的一个类的头文件中:

@interface MyClass : NSObject
{
NSString *string1;
NSString *string2;
}

- (void) methodOne: (NSString *) passedString;
- (void) methodTwo: (NSString *) passedString;

@end

在实现文件中,我这样做:

 #import MyClass.h

    @implementation MyClass

    - (void) methodOne: (NSString *) passedString
    {
       NSLog(@"%@", passedString);
       string1 = passedString;
    }

    - (void) methodTwo: (NSString *) passedString
    {
       NSLog(@"%@", passedString);
       string2 = passedString;
    }

我发现在执行此操作时与 [NSString alloc] initWithString:] 存在某种不一致。

如您所见, string1 和 string2 的处理方式完全相同,但发生的是 string1 正在设置,但 string2 仍然为空。当我稍后引用它时,我得到了一个错误的访问权限。

我想也许我正在将一个空字符串传递给methodTwo:所以我添加了证明它不是空的NSLog,但具有预期的字符串。

由于我在决定更改为之前已经注意到这种不一致:

        - (void) methodOne: (NSString *) passedString
        {
           NSLog(@"%@", passedString);
           string1 = passedString;
        }

        - (void) methodTwo: (NSString *) passedString
        {
           NSLog(@"%@", passedString);
           string2 = [[NSString alloc] initWithString: passedString];
        }

现在两个字符串都按预期工作。我的问题是为什么会出现这种不一致?

这不是我唯一一次发生这种情况。它发生在各种物体上。唯一似乎每次都有效的是alloc init。像 stringWithString: 这样的方法大部分时间都有效,但并非总是如此。

4

4 回答 4

2

这是因为在第一个示例中,您不保留或复制字符串。在您使用它之前,string2 会在某个时候被释放。string1 没问题实际上是纯粹的运气。您应该将代码更改为如下所示:

- (void) methodOne: (NSString *) passedString
{
   NSLog(@"%@", passedString);
   NSString* oldString = string1;
   string1 = [passedString copy];
   [oldString release];
}

- (void) methodTwo: (NSString *) passedString
{
   NSLog(@"%@", passedString);
   NSString* oldString = string2;
   string2 = [passedString copy];
   [oldString release];
}

并在 dealloc 中释放

-(void) dealloc
{
    [string1 release];
    [string2 release];
    // other stuff
    [super dealloc];
}

我强烈建议您为 string1 和 string2 创建属性来处理所有引用计数内容:

@interface MyClass : NSObject
{
NSString *string1;
NSString *string2;
}

- (void) methodOne: (NSString *) passedString;
- (void) methodTwo: (NSString *) passedString;

@property (copy) NSString* string1;
@property (copy) NSString* string2;  

@end

@imlementation MyClasss
@synthesize string1, string2;

- (void) methodOne: (NSString *) passedString
{
   NSLog(@"%@", passedString);
   [self setString1: passedString];
}

- (void) methodTwo: (NSString *) passedString
{
   NSLog(@"%@", passedString);
   [self setString2: passedString];
}

// dealloc as before

@end
于 2011-10-05T12:58:21.230 回答
1

您正在犯内存管理错误。当您将它们分配给您的 ivars 时,您必须保留或复制这些字符串(并在以后释放它们)。

有可能你仍然可以访问一个对象,即使它已经被释放,而它占用的内存还没有被覆盖。但是你不能依赖它。

于 2011-10-05T12:58:41.250 回答
0

如果传递的字符串是自动释放的,则分配它们时不会保留。常量字符串 (@str") 本质上永远不会被释放,需要保留由 stringWithFormat 等创建的字符串。

请出示来电者。

将@properties 与保留一起使用将消除许多保留问题。或者考虑使用 ARC,这样就不需要保留/释放/自动释放。

于 2011-10-05T12:59:06.007 回答
0

正如其他人在这个线程中所说的那样,您在这里遇到了一些内存管理问题,也许您不太了解 NSObjects 分配和保留的方式,您应该阅读 Objective-C 内存管理。同时,您可以采取两种方法来解决上述问题。

您可以将您的 NSString 成员变量(string1 和 string2)保留为您的类的属性,除了将这些声明为属性的一些其他功能会为它们提供 setter 和 getter 访问器,您将调用它们而不是 method1 和 method2。因此,这会将您的代码更改为在头文件中如下所示

@interface MyClass : NSObject
{
     NSString *string1;
     NSString *string2;
}

@property( nonatomic, retain)NSString* string1;
@property( nonatomic, retain)NSString* string1;

然后记得将以下内容添加到您的源文件中(通常在 @implementation MyClass 行之后的文件顶部)

@implementation MyClass
@synthesize string1;
@synthesize string2;

然后在您调用 method1 和 method2 的类中,您可以将代码更改为

    //Lets assume somewhere you've called an init Method for your MyClass Object, something like
    MyClass* myClassObject = [[MyClass alloc] init];

//you can then call the setters to set the string like so
[myClassObject setString1:@"some string"]; //or myClassObject.string1 = @"some string";
[myClassObject setString2:@"some string"]; //or myClassObject.string2 = @some other string";
//Calling these member variables either of the above ways is valid, I prefer the former as it's a bit easier on the eye for me

//and to get the values back out of the strings you could call
NSString* output = [myClassObject string1];
//or
NSString* output2 = myClassObject.string2;

现在您可能出于某种原因不想为 NSString 成员变量使用 @property,因此您可以修改原始源 (.m) 文件看起来像

@implementation MyClass

- (void) methodOne: (NSString *) passedString
{
   NSLog(@"%@", passedString);
   if( string1 != nil )
   {
      [string1 release];
   }
   string1 = [[NSString alloc] initWithString:passedString];
}

- (void) methodTwo: (NSString *) passedString
{
   NSLog(@"%@", passedString);
   if( string2 != nil )
   {
      [string2 release];
   }
   string2 = [[NSString alloc] initWithString:passedString];
}

这应该可以解决为什么您的字符串无效的问题,因为您不会覆盖内存并尝试以这种方式读回垃圾。如果它们不是 nil,你必须记住在你的 dealloc 中释放这些 NSString,否则你也会在那里得到内存泄漏。

希望这可以帮助。

于 2011-10-05T14:12:47.370 回答