1

初めて使用するときまでに初期化が完了していない可能性があるシングルトンへのアクセスの管理について質問があります。データベース ファイルを開いたり作成したりするための Core Data 初期化コードを含む StoriesModel というシングルトンを作成しました。初期化後、このシングルトンはその ManagedObjectContext をアプリ内のさまざまな画面で使用できるようにし、オブジェクトの作成、オブジェクトのテーブルの表示などを行います。

私が初めて電話したとき:

[StoriesModel 共有モデル].context

明らかに失敗します。Objective C では、この問題を解決するための良いパターンは何ですか? モデルクラスを使用する前に最初の呼び出しを行うことができることはわかっていますが、それが常に機能するとは限りません。私の以前の言語では、これを解決するためにイベントやデータ バインディングなどを使用していました。私はマルチスレッドが初めてです。

ヘッダーのコードは次のとおりです。

@interface StoriesModel : NSObject
+ (StoriesModel *)sharedModel;
@property (nonatomic,strong) NSManagedObjectContext *context;
@end

そして実装:

@implementation StoriesModel

+ (StoriesModel *)sharedModel
{
    static StoriesModel *sharedSingleton;

    @synchronized(self)
    {
        if (!sharedSingleton)
        {
            sharedSingleton = [[StoriesModel alloc] init];
            [sharedSingleton doInit];
        }
        return sharedSingleton;
    }
}
- (void)doInit
{
    // do some stuff that results in the context property being set in a few seconds
}
@end

ありがとう、

ジェリー

-- 変更されたコンテキスト ゲッターのサンプル:

- (NSManagedObjectContext *)context
{
    if (!self.storyDatabase)
    {
        NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        url = [url URLByAppendingPathComponent:@"StoryDatabase"];
        self.storyDatabase = [[UIManagedDocument alloc] initWithFileURL:url];

        // if file doesn't exist create it
        if (![[NSFileManager defaultManager] fileExistsAtPath:[self.storyDatabase.fileURL path]])
        {
            [self.storyDatabase saveToURL:_storyDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success)
             {
                 _context = self.storyDatabase.managedObjectContext;
                 [self populateSampleStories];
             }];
        }
        // if file exists but is closed open it
        else if (self.storyDatabase.documentState == UIDocumentStateClosed)
        {
            [self.storyDatabase openWithCompletionHandler:^(BOOL success)
             {
                 _context = self.storyDatabase.managedObjectContext;
             }];
        }
        // if file exists and is open use it
        else if (self.storyDatabase.documentState == UIDocumentStateNormal)
        {
            _context = self.storyDatabase.managedObjectContext;
        }
    }
}
4

4 に答える 4

4

pthread_onceordispatch_onceを使用して、シングルトンの初期化子が 1 回だけ実行されるようにすることができます。

dispatch_once例: Objective C で GCD の dispatch_once を使用してシングルトンを作成する

于 2013-02-28T17:55:02.977 に答える
2

Cocoa samuraiは、彼のブログでこの問題について説明しています。このコードピースは、シングルトンの作成を高速化し、マルチスレッドアプリで機能するはずです。

  +(MyClass *)singleton {
  static dispatch_once_t pred;
  static MyClass *shared = nil;

  dispatch_once(&pred, ^{
    shared = [[MyClass alloc] init];
  });
  return shared;
  }

このリンクをチェックしてください
http://cocoasamurai.blogspot.com/2011/04/singletons-your-doing-them-wrong.html

于 2013-02-28T17:57:38.687 に答える
0

ここでの基本的な設計の質問は、シングルトンStoriesModelの作成中に役立つことを実行できるかどうかです。そして、これらを行うとコードが複雑になりますか?

私の好みは作ることです

 [StoriesModel sharedModel].context

初期化を行い、準備ができたときにのみ戻ります。

 NSBlockOperation *op=[NSBlockOperationWithBlock:(^{
      StoryContext *context=[StoriesModel sharedModel].context;
      [context doSomething];
 };

これを別のスレッドでスピンオフし、他のタスクを続行します。


たとえば、ゲッターは非常に単純である可能性があります。

- (NSManagedObjectContext *)context
{
    if (self.storyDatabase) return self.storyDatabase;
    self.storyDatabase=[self spendSomeTimeAt: theLibrary];  // slow!
    return self.storyDatabase;
}

初期化コードは次のようになります。

  NSBlockOperation *op=[NSBlockOperationWithBlock:(^{
  StoryContext *context=[StoriesModel sharedModel].context;
        [context doSomething];
  };
  NSOperatorQueue *q=[self workQueue];
  [q addOperation: op];
  // proceed to do some other things while visiting the library
  [self initializeGraphics];
  [self cook: dinner];
  [self refactor: yourCode];

しかし、これはすべて、少し時期尚早な最適化をしのぐものです。初めてコンテキストを設定することがボトルネックになるかどうかわからない場合は、簡単な方法でそれを行い、雨の午後にこれに戻ってください。

于 2013-02-28T18:46:48.653 に答える
0

シングルトンにアクセスしようとしているスレッドをブロックしても大丈夫かどうかに大きく依存します。もしそうなら、を使ってみることができますdispatch_semaphore。基本的に、「いくつかの作業が完了するまで、この呼び出しをブロックする」と言うことができます (また、一連のリソースを管理することもできますが、これとは関係ありません)。または、ブールdoneivar とwhile(!done){}.

また、sharedModel と doInit に完了ブロックまたは post とNSNotification.

于 2013-02-28T20:56:01.550 に答える