为什么变量的隐式初始化在 iPhone 上不一致?

发布于 2024-12-08 10:36:24 字数 1340 浏览 1 评论 0原文

所以这是我的场景 - 在类的头文件中我这样做:

@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: 这样的方法在大多数情况下都有效,但并非总是如此。

So here is my scenario -- In the header file of a class I do:

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

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

@end

In the implementation file I do this:

 #import MyClass.h

    @implementation MyClass

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

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

What I am finding is that there is some kind of inconsistency when doing this versus [NSString alloc] initWithString:].

As you can see string1 and string2 are treated exactly the same, but what is happening is that string1 is getting set, but string2 is remaining empty. I get a bad access when I reference it later.

I thought maybe I was passing an empty string to methodTwo: so I added that NSLog which proves that it is not empty, but has the expected string.

Since I have noticed this inconsistency before I decided to change to this:

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

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

Now both strings are working as expected. My question is why is there this inconsistency?

This is not the only time this has happened to me. It has happened with all kinds of objects. The only thing that seems to work every time is alloc init. Methods like stringWithString: work most of the time, but not always.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秋意浓 2024-12-15 10:36:24

这是因为在第一个示例中,您没有保留或复制字符串。 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

It's because in the first example, you don't retain or copy the strings. string2 is getting deallocated at some point before you use it. It's actually pure luck that string1 is OK. You should change your code to be something like this:

- (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];
}

and release in dealloc

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

I strongly recommedn you create properties for string1 and string2 to handle all that reference counting stuff:

@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
西瓜 2024-12-15 10:36:24

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

即使对象已被释放,但其占用的内存尚未被覆盖时,您仍然可以访问该对象。但你不能依赖它。

You are making memory management errors. You have to retain or copy the strings when you assign them to your ivars (and release them later).

It is possible that you can still access an object even though it has been deallocated when the memory it occupied has not been overwritten yet. But you cannot rely on it.

七分※倦醒 2024-12-15 10:36:24

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

请向调用者展示。

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

If the passed strings are autoreleased there is no retain when they are assigned. Constant strings (@str") essentially are never released, created strings such as by stringWithFormat need to be retained.

Please show the callers.

Using @properties with retain will eliminate many retain issues. Or consider using ARC, that eliminates the need for retain/release/autorelease.

面如桃花 2024-12-15 10:36:24

正如其他人在这个线程中所说的那样,您在这里遇到了一些内存管理问题,也许您不太了解 NSObject 分配和保留的方式,您应该阅读 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];
}

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

希望这有帮助。

As others have stated in this thread you have some memory management issues here, perhaps you aren't quite understanding the way that NSObjects get allocated and retained, you should read up on Objective-C memory management. In the mean time there are two approaches you could take to solve your above issue.

You could have your NSString member variables (string1 & string2) kept as properties of your class, aside from some other functionality declaring these as properties would give them setter and getter accessors, that you would call instead of method1 and method2. So this would change your code to look like the following in your header file

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

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

Then remember to add the following to your source file (typically at the top of the file after the @implementation MyClass line)

@implementation MyClass
@synthesize string1;
@synthesize string2;

Then in the class where you were calling method1 and method2 from you can change the code to look like

    //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;

Now you may for some reason not want to use an @property for the NSString member variables, so you could modify your original source (.m) file to look like

@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];
}

That should solve the issue of why your strings aren't valid, as you wont be overwriting the memory and trying to read back garbage this way. You will have to remember to release these NSStrings in your dealloc if they are not nil, otherwise you'll get a memory leak there too.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文