2017-07-20 7 views
0

Firebaseはクロージャで実行されるため、別のスレッドで実行されます。 Firebaseがデータの読み込みを終了したら、私は補完ハンドラを呼び出そうとします。Firebaseがコールバック関数を呼び出した後にmain_threadに戻る方法は?

しかし、私はそれを実行するエラーがあります。 "スレッド1:EXC_BAD_ACCESS(コード= EXC_1386_GPFLT)"私は間違ったスレッドに関する問題を知っていますが、それを修正する方法はわかりません。私は、ビューコントローラ上のコンポーネントの状態を編集しようとしています。助けてください

func refreshData(completionHandler:@escaping (Bool)->()) { 
    //I ignore some unrelated statements here 
    //.... 
    //Reloading the database 
    ref.observe(.value, with: { snapshot in 
     var newItems: [Task] = [] 
     self.num_of_tasks = Int(snapshot.childrenCount) 
     for item in snapshot.children { 
      let taskItem = Task(snapshot: item as! DataSnapshot) 
      newItems.append(taskItem!) 
     } 
     let merged = drafts + newItems 
     self.items = merged 
     self.tableView.reloadData() 
     completionHandler(true) //The line causes error 
    }) 
} 

私はこの関数をviewDidLoadで呼び出します。クラッシュログと

override func viewDidLoad() { 
    super.viewDidLoad() 
    self.refreshControl = UIRefreshControl() 
    self.refreshControl!.addTarget(self, action: #selector(refreshData),for: .valueChanged) 
    self.refreshControl!.attributedTitle = NSAttributedString(string: "Update the data") 
    refreshData{ _ in 
     self.refreshControl!.endRefreshing() 
    } 
} 

更新:UDPATE

> * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x111606db0) 
>  frame #0: 0x0000000111606db0 CoreFoundation`__NSSingleObjectArrayI 
>  frame #1: 0x000000010f61248a MGSupport`thunk at TaskTableViewController.swift:0 * frame #2: 0x000000010f612294 
> MGSupport`TaskTableViewController.(self=0x00007fa6ead25860, 
> completionHandler=0x000000010f6124e0 MGSupport`partial apply forwarder 
> for reabstraction thunk helper from @callee_unowned @convention(block) 
> (@unowned ObjectiveC.ObjCBool) ->() to @callee_owned (@unowned 
> Swift.Bool) ->() at TaskTableViewController.swift) ->()) -> 
>()).(closure #1).(closure #1) at TaskTableViewController.swift:95 
>  frame #3: 0x000000010f6122d7 MGSupport`thunk at TaskTableViewController.swift:0 
>  frame #4: 0x00000001140c94a6 libdispatch.dylib`_dispatch_call_block_and_release + 12 
>  frame #5: 0x00000001140f205c libdispatch.dylib`_dispatch_client_callout + 8 
>  frame #6: 0x00000001140d340b libdispatch.dylib`_dispatch_main_queue_callback_4CF + 411 
>  frame #7: 0x0000000111311909 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9 
>  frame #8: 0x00000001112d7ae4 CoreFoundation`__CFRunLoopRun + 2164 
>  frame #9: 0x00000001112d7016 CoreFoundation`CFRunLoopRunSpecific + 406 
>  frame #10: 0x000000011548ea24 GraphicsServices`GSEventRunModal + 62 
>  frame #11: 0x0000000111e59134 UIKit`UIApplicationMain + 159 
>  frame #12: 0x000000010f62c687 MGSupport`main at AppDelegate.swift:14 
>  frame #13: 0x000000011413e65d libdyld.dylib`start + 1 

デバッグ: 私はブレークポイントを設定しようとした私は、関数がのviewDidLoad(から呼び出されたときにのみ、最初の時間がcompletionHandlerが正常に呼び出されることを見出しました)。しかし、ユーザーが画面をスクロールダウンし、refreshControlの自動呼び出しによってrefreshData関数を再度呼び出すと、もうcompletionHandlerにアクセスできなくなります。何か案が?

+0

は、あなたの質問とクラッシュログを追加するためのデフォルトの補完ブロックを与える... – Subramanian

+0

は、私はすでにクラッシュログを添付main.asyncブロックコール – Joshua

+0

@SubramanianにreloadDataとcompletionHandlerを置きます。ありがとう – Chen

答えて

2

それは理由refreshControlセレクタのです。セレクタには完了ハンドラがありません。また、完了時刻ブロックが実行しようとしているが、リフレッシュ制御の完了ブロックがない場合は、refreshControlの値が変更されたときに発生します。

だから、もっと自分のrefreshData(_:)

func refreshData(completionHandler:@escaping (Bool)->() = { _ in }) { 
    //You code is here. 
} 
+0

はい!私はちょうどそれを考え出した。私はその関数呼び出しを別の関数の中の補完ハンドラでラップしようとしました! – Chen

+0

それのために別の機能を作成する必要はありません。デフォルト完了ハンドラで1つの関数を使用できます。 – Subramanian

0

以下のことを試してみてください。閉鎖内でselfが利用可能な場合は、ブレークポイントを使用してチェックすることもできます。

refreshData{ [weak self] _ in 
     if let _ = self { 
      self?.refreshControl!.endRefreshing() 
     } 
    } 
関連する問題