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

これで、両方の文字列が期待どおりに機能しています。私の質問は、なぜこの矛盾があるのか​​ということです。

これが私に起こったのはこれだけではありません。それはあらゆる種類のオブジェクトで起こりました。毎回機能するように見えるのは、allocinitだけです。stringWithStringのようなメソッド:ほとんどの場合機能しますが、常に機能するとは限りません。

4

4 に答える 4

2

これは、最初の例では、文字列を保持またはコピーしないためです。string2は、使用する前のある時点で割り当てが解除されています。string1がOKであるのは実際には純粋な運です。コードを次のように変更する必要があります。

- (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

メモリ管理エラーを起こしています。文字列を ivar に割り当てるとき (および後で解放するとき) に、文字列を保持またはコピーする必要があります。

オブジェクトが占有していたメモリがまだ上書きされていない場合、オブジェクトの割り当てが解除されていても、オブジェクトにアクセスできる可能性があります。しかし、あなたはそれに頼ることはできません。

于 2011-10-05T12:58:41.250 に答える
0

このスレッドで他の人が述べているように、メモリ管理の問題がいくつかあります。おそらく、NSObject が割り当てられて保持される方法をよく理解していないため、Objective-C のメモリ管理を読む必要があります。それまでの間、上記の問題を解決するために取ることができる 2 つのアプローチがあります。

NSString メンバー変数 (文字列 1 と文字列 2) をクラスのプロパティとして保持することができますが、これらをプロパティとして宣言する他の機能は別として、メソッド 1 とメソッド 2 の代わりに呼び出すセッター アクセサーとゲッター アクセサーを提供します。したがって、これにより、ヘッダー ファイルでコードが次のように変更されます。

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

次に、メソッド1とメソッド2を呼び出していたクラスで、コードを次のように変更できます

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

これにより、メモリを上書きしてこの方法でガベージを読み戻そうとしないため、文字列が有効でない理由の問題が解決するはずです。これらの NSStrings が nil でない場合は、dealloc で解放することを忘れないでください。そうしないと、そこでもメモリ リークが発生します。

お役に立てれば。

于 2011-10-05T14:12:47.370 に答える
0

渡された文字列が自動解放されている場合、それらが割り当てられたときに保持されません。定数文字列 (@str") は本質的に解放されることはなく、stringWithFormat などによって作成された文字列は保持する必要があります。

発信者に見せてください。

@properties を保持とともに使用すると、多くの保持の問題が解消されます。または、保持/解放/自動解放の必要性を排除する ARC の使用を検討してください。

于 2011-10-05T12:59:06.007 に答える