1

私はアプリの一部をAppleのCoreDataRecipesサンプルコードに基づいています。

http://developer.apple.com/library/ios/#samplecode/iPhoneCoreDataRecipes/Introduction/Intro.html

いくつかの変更を加えた後、私は導入したはずのバグを追跡するのにかなりの時間を費やしましたが、アップルのコードに存在する2行のコードを削除することで解決しました。

NSManagedDataObjectレシピに作成者属性を追加しました。これは、私が知る限り、レシピがすでに持っている他の文字列属性と実装が同じです。IngredientDetailViewControllerによって制御されるモーダルビューに出入りした後、私の新しい属性はゾンビになりました。IngredientDetailViewControllerのdeallocメソッドは

- (void)dealloc {
    [recipe release];
    [ingredient release];
    [super dealloc];
}

バグを突き止めた後、レシピと材料(別のNSManagedObject)のリリースをコメントアウトしたところ、アプリが機能しているように見えました。私のコードは、これらのリリース呼び出しの有無にかかわらず機能することを発見しました。バグは私が行った別の変更によって修正されたに違いありません。私は今疑問に思っています

  1. アップルのサンプルコードが元々このように書かれたのはなぜですか?
  2. NSManagedObjectレシピの元の属性についてはどうでしたか?つまり、dealloc呼び出しからのゾンビ化の影響を受けませんでしたか?

上記が私の無知を十分に示していない場合、私はObjective CとiPhoneの開発に不慣れであることを指摘する必要がありますが、ここで何が起こっているのかを本当に理解したいと思います。

コメントに応じて編集および更新:

これらの行のコメントを外してゾンビの作成を複製することはできません。明らかに、バグシューティング中の別の変更でうまくいきました。私が最初に尋ねたもののいくつかは現在無効ですが、機能がこれらの呼び出しの有無にかかわらず同じように見えるため、NSManagedObjectsのリリースの使用に関してさらに混乱しました。今の私の主な質問は、彼らがそこにいるべきかどうかということです。IngredientDetailViewに保存すると、クラッシュが発生していました。ヘッダーは次のとおりです。

@class Recipe, Ingredient, EditingTableViewCell;

@interface IngredientDetailViewController : UITableViewController {
@private
    Recipe *recipe;
    Ingredient *ingredient;

    EditingTableViewCell *editingTableViewCell;
}

@property (nonatomic, retain) Recipe *recipe;
@property (nonatomic, retain) Ingredient *ingredient;

@property (nonatomic, assign) IBOutlet EditingTableViewCell *editingTableViewCell;

@end

およびsaveメソッド:

- (void)save:(id)sender {
NSManagedObjectContext *context = [recipe managedObjectContext];
/*
 If there isn't an ingredient object, create and configure one.
 */
if (!ingredient) {

    self.ingredient = [NSEntityDescription insertNewObjectForEntityForName:@"Ingredient" 
                                                    inManagedObjectContext:context];

    [recipe addIngredientsObject:ingredient];


    ingredient.displayOrder = [NSNumber numberWithInteger:[recipe.ingredients count]];


}
/*
 Update the ingredient from the values in the text fields.
 */
EditingTableViewCell *cell;

cell = (EditingTableViewCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
ingredient.name = cell.textField.text;

cell = (EditingTableViewCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
ingredient.amount = cell.textField.text;
/*
 Save the managed object context.
 */
NSError *error = nil;

if (![context save:&error]) {

    /*
     Replace this implementation with code to handle the error appropriately.

     abort() causes the application to generate a crash log and terminate. 
     You should not use this function in a shipping application, although it may be useful during development. 
     If it is not possible to recover from the error, display an alert panel that instructs the user to quit the 
     application by pressing the Home button.
     */
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

[self.navigationController popViewControllerAnimated:YES];
NSLog(@"in ingredient detail save after ingredient pop; - recipe.author is %@", recipe.author);
}

私は新しいユーザーなので、ここにデータモデルのスクリーンショットを置くことはできません。そのため、ここにリンクがあります。データモデルのスクリーンショット

そして最後にレシピヘッダー:

@interface ImageToDataTransformer : NSValueTransformer {
}
@end


@interface Recipe : NSManagedObject {
}

@property (nonatomic, retain) NSString *instructions;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *overview;
@property (nonatomic, retain) NSString *prepTime;
@property (nonatomic, retain) NSSet *ingredients;
@property (nonatomic, retain) UIImage *thumbnailImage;
@property (nonatomic, retain) NSString *author;
@property (nonatomic) BOOL *isDownloaded;
@property (nonatomic) BOOL *isSubmitted;
@property (nonatomic, retain) NSString *uniqueID;
@property (nonatomic) float averageRating; 
@property (nonatomic) float numberOfRatings;


@property (nonatomic, retain) NSManagedObject *image;
@property (nonatomic, retain) NSManagedObject *type;

@end


@interface Recipe (CoreDataGeneratedAccessors)
- (void)addIngredientsObject:(NSManagedObject *)value;
- (void)removeIngredientsObject:(NSManagedObject *)value;
- (void)addIngredients:(NSSet *)value;
- (void)removeIngredients:(NSSet *)value;
@end

再度、感謝します。

4

2 に答える 2

2

管理対象オブジェクトを解放するのは、それを自分で保持していた場合だけです。あなたのプロパティ定義は、レシピと材料オブジェクトを保持していると言っているので、成分ビューコントローラーの割り当てが解除されると、レシピと成分オブジェクトを解放する必要があります。

myIngredientViewController.ingredient = anIngredient のようなことをすると、次のようなメソッドを呼び出すようなものになります。

- (void)setIngredient:(Ingredient *)ing {
  [self willChangeValueForKey:@"ingredient"];
  Ingredient *oldIngredient = ingredient;
  ingredient = [ing retain];
  [oldIngredient release];
  [self didChangeValueForKey:@"ingredient"];
}

したがって、save メソッドで self.ingredient = ... を割り当てると、オブジェクトを自分で保持することになります。そのオブジェクトに所有権があるため、dealloc でそれを解放する必要があります。

別の言い方をすれば、管理対象オブジェクト コンテキストは所有権を持っているため保持カウントに 1 を追加し、所有権を維持したいので保持カウントに 1 を追加しました。所有権を解放するときに、dealloc 中にそれを解放すると、保持カウントが 1 減り、管理対象オブジェクト コンテキストがそれを解放すると、保持カウントがゼロになり、割り当てが解除されます。

これが通常のオブジェクトの動作方法であり、ほとんどの状況で管理対象オブジェクトを扱う方法ですが、管理対象オブジェクトにはいくつかの注意事項があります。前の投稿者が示したように、管理対象オブジェクトのライフサイクルは管理対象オブジェクト コンテキストによって制御されます。管理対象オブジェクトに発生する可能性のあるさまざまな事態は、オブジェクトがまだ存在していても、コンテキストで削除されたり、コンテキストで障害が発生したり、別のデータで再利用されたりする可能性があることを意味します。

通常はそれについて心配する必要はありませんが、メモリを管理する必要がある独自のインスタンス変数を持つカスタム マネージド オブジェクトを使用する場合、またはそれらが作成、フェッチ、フォールトに変わるときに実行したいその他のことを行う場合などの場合は、awakeFromInsert、awakeFromFetch、willTurnIntoFault、didTurnIntoFault などを確認する必要があります。

しかし、これらは高度なものであり、より複雑なシナリオに入るまでは必要ありません。

HTH

于 2011-07-29T04:39:05.643 に答える
2

Core Data のドキュメントを参照してください。Core Data は管理対象オブジェクトのライフサイクルを「所有」しているため、それらをまったく解放するべきではありません。

于 2011-05-27T14:43:03.103 に答える