2017-09-10 31 views
0

ここで関数を使用して、非同期ブロック(データベースクエリのみ)から値を返します。問題はメモリが原因でアプリケーションがフリーズして終了することです。メインスレッドでこれを実行する方が良いかどうか、それを避けるべきかアドバイスを求めていますか?他のスレッドで実行されていることに注意してください。非同期ブロック戻りの問題

- (NSString *)databaseQuery:(NSString*)ingredient { 
    __block NSString *valueType = nil; 
    __block BOOL done = NO; 
    [[[_ref child:@"ingredients"] queryEqualToValue:valueType childKey:ingredient] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { 
     for (FIRDataSnapshot *child in snapshot.children) { 
      valueType = child.value; 
     } 
     done = YES; 
    } withCancelBlock:^(NSError * _Nonnull error) { 
     NSLog(@"%@", error.localizedDescription); 
     done = YES; 
    }]; 

    while (!done) { 
     [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 
    } 
    return valueType; 
} 

UPDATE 1:以下のコードを使用しようとし、それは同じ結果を生成します。

- (NSString *)databaseQuery:(NSString*)ingredient { 
    __block NSString *valueType = nil; 
    dispatch_semaphore_t sem = dispatch_semaphore_create(0); 
    FIRDatabaseQuery *query = [[_ref child:@"ingredients"] queryEqualToValue:valueType childKey:ingredient] ; 
    [query observeEventType:FIRDataEventTypeChildAdded 
        withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { 
         valueType = snapshot.value; 
         dispatch_semaphore_signal(sem); 
        } 
      withCancelBlock:^(NSError * _Nonnull error) { 
       NSLog(@"%@", error.localizedDescription); 
       dispatch_semaphore_signal(sem); 
      }]; 

    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 
    return valueType; 
} 

2 UPDATE:機能ブロックから復帰しないよう

形式を変更。 FIRDatabaseQueryのみを返します。

- (FIRDatabaseQuery *)databaseQuery:(NSString*)ingredient { 
    __block NSString *valueType = nil; 
    FIRDatabaseQuery *query = [[_ref child:@"ingredients"] queryEqualToValue:valueType childKey:ingredient]; 
    return query; 
} 

以下の手順は別の手順です。返される値を除いて、nullです。解決

query = [self databaseQuery:substring]; 
      [query observeEventType:FIRDataEventTypeChildAdded 
          withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { 
           idValue = snapshot.value; 
          } 
        withCancelBlock:^(NSError * _Nonnull error) { 
         NSLog(@"%@", error.localizedDescription); 
        }]; 
      NSLog(@"%@", idValue); 
+0

メモリに関する問題の詳細を教えてください。どの行/何の例外はありますか? whileループ内でNSRunLoopを実行する代わりに 'dispatch_group_t'を使用しようとしましたか? –

+0

ディスパッチグループtを使ってみることができます。メモリは問題ではなく、アプリケーションの結果がスレッドに固執しているだけです。 –

+0

同じ結果を出した別のアイデアを試してみました。 –

答えて

0

:私はNSRunLoopを避けたいと思うよう限り、問題は、私は1つがすでに実行していたと私はそれを停止していなかったということでした。

回答はCFRunLoopStop(CFRunLoopGetCurrent());をアプリケーションに追加することでした。セマフォを使用してこれを置き換える必要があります。

問題は、これはループにあります。最初のアイテムが検索された後、それが止まり、再びハングします。これを解決するために、ディスパッチグループを使用しました。

注:ループの前にディスパッチグループとidValueを宣言します。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
       dispatch_group_enter(_groupSearch); 
       dispatch_async(queue, ^{ 
       [[self databaseQuery:searchItem] observeEventType:FIRDataEventTypeChildAdded 
           withBlock:^(FIRDataSnapshot * _Nonnull snapshot) { 
            idValue = snapshot.value; 
            dispatch_group_leave(_groupSearch); 
           } 
         withCancelBlock:^(NSError * _Nonnull error) { 
          NSLog(@"%@", error.localizedDescription); 
          dispatch_group_leave(_groupSearch); 
          }]; 
       }); 
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        dispatch_group_wait(_groupSearch, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC))); 
        dispatch_sync(queue, ^{ 
         if (idValue != NULL) { 
          NSLog(@"%@",idValue); 
         } 
        }); 
       });