4

オブジェクトを遅延して作成し、それを弱いプロパティとして格納するクラスがあります。他のクラスがこのオブジェクトを要求する場合がありますが、オブジェクトの割り当てが解除されないようにするには、明らかにオブジェクトへの強力な参照を保持する必要があります。

// .h
@interface ObjectManager
@property(nonatomic, weak, readonly) NSObject *theObject;
@end

// .m
@interface ObjectManager ()
@property(nonatomic, weak, readwrite) NSObject *theObject;
@end

@implementation ObjectManager
- (NSObject *)theObject
{
    if (!_theObject) {
        _theObject = [[NSObject alloc] init];
        // Perform further setup of _theObject...
    }
    return _theObject;
}
@end

スキームがXcodeがデバッグ用にビルドするように設定されている場合、問題なく動作します。オブジェクトは呼び出しobjectManagerInstance.theObjectて戻ることができますtheObject

スキームがリリース用にビルドするように設定されている場合、次をtheObject返しますnil

// Build for Debug:
NSObject *object = objectManagerInstance.theObject;
// object is now pointing to theObject.

// Build for Release:
NSObject *object = objectManagerInstance.theObject;
// object is now `nil`.

私の推測では、コンパイラーは_theObject、アクセサーメソッド自体でそれ以上使用されていないことを確認してコードを最適化しているため、nil戻る前にweak変数がに設定されています。変数を実際に返す前に、強力な参照を作成する必要があるようです。これは、ブロックを使用して行うことしか考えられませんが、面倒なので、避けたいと思います。

ivarがすぐに無効になるのを防ぐためにreturnタイプで使用できるキーワードの種類はありますか?

4

2 に答える 2

8

ほとんどの場合、DEBUGビルドにより、オブジェクトは自動解放プールに「機能」するのに十分な時間留まりますが、RELEASEビルドにより、オプティマイザーはもう少し制御フロー分析を実行し、その後自動解放のチャタリングを排除します。

率直に言って、コンパイラがリリースビルドで、コードが機能しないという警告を発していないことはバグです(すばらしい簡潔な例があるので、ファイルしてください)。

強力な参照が必要なものが参照を取得する機会が得られるまで、オブジェクトへの強力な参照をどこかに維持する必要があります。

私はこのようなものがうまくいくかどうか疑問に思っています:

- (NSObject *)theObject
{
    NSObject *strongObject;
    if (!_theObject) {
        strongObject = [[NSObject alloc] init];
        _theObject = strongObject;
        // Perform further setup of _theObject...
    } else {
        strongObject = _theObject;
    }
    return strongObject;
}

つまり、上記は、内部的に弱参照維持しながら、自動解放されたオブジェクトを返すファクトリメソッドに似ています。しかし、オプティマイザーは賢すぎて上記を破る可能性があります。

于 2013-02-27T18:28:54.950 に答える
4

あなたはオプティマイザーに噛まれています。

は弱参照であるため_theObject、システムは自由にそれを取り除き、保持されていないときはいつでも弱参照をゼロにします。ただし、すぐに実行する必要はありません。

レイジーインスタンシエーターでは、新しく作成されたオブジェクトが保持されることはありません。オプティマイザーはこれを見て、「わあ!いつでもこの参照をゼロにすることができます!なぜ今すぐやらないのですか!」と言います。そして、あなたがそれを知る前に、あなたはnilを返しています。

あなたがしたいのは、関数のスコープの間続く暗黙的に強い参照のために、遅延インスタンス化されたオブジェクトをローカル変数に割り当てることです。また、objc_precise_lifetimeアノテーションを使用して、完全なスコープが本当に必要であることをコンパイラーに通知する必要があります。

規格の詳細については、こちらのページをご覧ください

于 2013-02-27T18:35:41.043 に答える