2016-08-21 7 views
7

私はARCと弱/無所有の自己(Shall we always use [unowned self] inside closure in Swift)についてのstackoverflowとappleのドキュメントに関する研究を行ってきました。私は、強いリファレンスサイクルと、メモリリークの原因となるものではないことについての基本的な考え方を得ています。しかし、私はクロージャーでWeak/Unownedの自己を使用するときに頭を抱えようとしています。むしろ "理論"に入るのではなく、私が持っている底の3つの事例に関して親切に説明することができれば、本当に助けになると思います。私の質問は閉鎖と結果の弱い例

  1. である、しかし(私が?。私はUIViewのは、自己に関連付けられていないことをどこかで見たので、ケース2のために必要がないと考え、それらのすべてに弱い自己を入れて、それはOK、私が何を置く場合です私の頭痛の原因になるものはありますか?

  2. 答えが「いいえ」なら、私は3つの場合すべてどこに弱い自己を置くこともできません。 ..たとえば、このVCのときにプログラムがクラッシュします....

  3. これは私がweakSelfを使用する方法です 閉鎖の外側で、私は弱いvarを入れたweakSelf =自己 それから閉鎖のすべての自己をweakSelfで置き換えますか? いいですか?私のコードの大部分

--Update--

Case 1: 
FIRAuth.auth()?.signInWithCredential(credential, completion: { (user: FIRUser?, error: NSError?) in 
    self.activityIndicatorEnd() 
    self.performSegueWithIdentifier(SEGUE_DISCOVER_VC, sender: self) 
}) 

Case 2: 
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.1, animations: { 
    self.messageLbl.alpha = 0.5 
}) 

Case 3: 
//checkUserLoggedIn sends a request to firebase and waits for a response to see if the user is still authorised 
checkUserLoggedIn { (success) in 
    if success == false { 
     // We should go back to login VC automatically 

    } else {   
     self.discoverTableView.delegate = self 
     self.discoverTableView.dataSource = self 

     // Create dropdown menu 
     let menuView = BTNavigationDropdownMenu(navigationController: self.navigationController, title: self.dropDownItems.first!, items: self.dropDownItems) 

     menuView.didSelectItemAtIndexHandler = {[weak self] (indexPath: Int) ->() in 
      if indexPath == 0 { 
       self?.mode = .Closest 
       self?.sortByDistance() 

      } else if indexPath == 1 { 
       self?.mode = .Popular 
       self?.sortByPopularity() 

      } else if indexPath == 2 { 
       self?.mode = .MyPosts 
       self?.loadMyPosts() 

      } else { 
       print("Shouldnt get here saoihasiof") 
      } 
     } 

    // Xib 
     let nib = UINib(nibName: "TableSectionHeader", bundle: nil) 
     self.xibRef = nib.instantiateWithOwner(self, options: nil)[0] as? TableSectionHeader 
     self.discoverTableView.registerNib(nib, forHeaderFooterViewReuseIdentifier: "TableSectionHeader") 

     // Set location Manager data 
     self.locationManager.delegate = self 
     self.locationManager.desiredAccuracy = kCLLocationAccuracyBest 

     // Check location service status 
     if self.locationAuthStatus == CLAuthorizationStatus.AuthorizedWhenInUse { 
      // Already authorised 
      self.displayMessage.hidden = false 

     } else if self.locationAuthStatus == CLAuthorizationStatus.NotDetermined { 
      // Have not asked for location service before 
      let storyboard = UIStoryboard(name: "Main", bundle: nil) 
      let vc = storyboard.instantiateViewControllerWithIdentifier("LocationVC") as! LocationVC 
      vc.locationVCDelegate = self 
      self.presentViewController(vc, animated: true, completion: nil) 

     } else { 
      let alertController = UIAlertController(title: "Enable Location", message: "location is required to load nearby posts", preferredStyle: .Alert) 
      let cancelAction = UIAlertAction(title: "Cancel", style: .Default, handler: nil) 
      let settingsAction = UIAlertAction(title: "Settings", style: .Default, handler: { (action: UIAlertAction) in 
       let settingsUrl = NSURL(string: UIApplicationOpenSettingsURLString) 
       if let url = settingsUrl { 
        UIApplication.sharedApplication().openURL(url) 
       } 
      }) 
      alertController.addAction(settingsAction) 
      alertController.addAction(cancelAction) 
      self.presentViewController(alertController, animated: true, completion: nil) 

      self.displayMessage.hidden = false 
      self.displayMessage.text = "Could not determine your location to find nearby posts. Please enable location Service from settings" 
     } 

     // Styling 
     self.refreshBtn.tintColor = COLOR_NAVIGATION_BUTTONS 
     self.discoverTableView.backgroundColor = COLOR_DISCOVERVC_TABLEVIEW_BACKGROUND 

     // Allow navigation bar to hide when scrolling down 
     self.hidingNavBarManager = HidingNavigationBarManager(viewController: self, scrollView: self.discoverTableView) 

     // Allow location to start updating as soon as we have permission 
     self.locationManager.startUpdatingLocation() 
    } 
} 
はすべてが、アクションのいずれかが行われる前に、インターネット接続があるかどうかを確認いずれかであることクロージャ内にラップされたケース3のように見えます。だから私はどこにでも弱い自己を持っているかもしれない? 4. 私はこの閉鎖は弱い/所有されていない自己を持っていないにもかかわらず、それは強い参照を作成することはありませんと言うことは修正頂く場合(およびメモリに関する

--update 2--

Case 4: 
// The haveInternetConnectivity function checks to see if we can reach google within 20 seconds and return true if we can 
haveInternetConnectivity { (success) in 
    if success == false { 
     self.dismissViewControllerAnimated() 
    } else {   
     self.label.text = "You are logged in" 
     self.performSegueWithIdentifier("GoToNextVC") 
    } 
} 

質問リーク)は、完了ブロックが実行される前にVCが破棄されても、インターネット状態を確認したときにXcodeがコンプリートブロック内でコードを実行しようとし、自己がもう存在しないため何もしません(クラッシュしません)。コードがクロージャの最後の行に到達すると、自己への強い参照が破壊され、VCの割り当てが解除されます。

ので

が いずれかの方法だけで(試してみて、それを実行するために反対し、何も起こらないよう)Xcodeのがより良い練習が、私の手には何の問題を意味しているものの行を無視することを意味し、その場合には、[弱いセルフ]を入れて

答えて

13

「弱い参照は使用できますか?」ではなく、「弱い参照を使用する必要がありますか」という質問があります。弱い参照を使用して、強い参照サイクルを回避するか、またはクロージャが処理された後に何かにぶら下がるのを防ぐために使用します。しかし、あなたができるので弱い参照を追加するだけではありません。ケース1では

  1. 、あなたはおそらく[weak self]を使用したいです。どうして?認可の進行中にView Controllerが終了された場合、実際には切断されたView Controllerへの参照を保持したいのですか?この場合はおそらくないでしょう。

  2. ケース2では、理論的にはanimationブロックに[weak self]を使用できますが、なぜですか?理由はありません。弱い参照は、ハンドラやクロージャ変数を使って行うことですが、アニメーションブロックの場合はユーティリティは提供されないため、そこでは行いません。ここでweakを使用すると、関係するメモリセマンティクスの誤解が示唆されます。

  3. ケース3では、2つの別々の問題があります。オブジェクト自身の閉鎖は、自分自身を参照しているので、おそらく[unowned self]を使用する必要がありますdidSelectItemAtIndexHandler

    • 、。

      私はあなたが実際にBTNavigationDropdownMenu(おそらくその初期化子は、ナビゲーションコントローラに自分自身を追加しているが、そうならばそれは、私見うまく設計された初期化子ではない)ことを使用して表示されないように、それは、議論の余地が問題になることがあります。

      しかし、一般的な考え方として、オブジェクトがまだ周囲にあるときにのみ呼び出すことができるが、それ自身ではオブジェクトを保持させるべきではないハンドラクロージャがあるときは、[unowned self]を使用します。

    • クロージャでは、それは完了ハンドラかどうかです。その場合は、selfが終了し、checkUserLoggedInが終了したビューコントローラへの参照を保持したくない場合は、[weak self]を使用する必要があります。しかし、[unowned self]を使用したくない場合は、クロージャが実行されるまでにリリースされていれば、ポインタがぶら下がります。余談として

      、あなたが考える:ビットunswiftyある

      weak var weakSelf = self 
      

      checkUserLoggedInクロージャの開始時に[weak self]パターンを使用します。 weak var weakSelf = ...を使用したいという例がある場合は、そのパターンを使用する場所の例を含め、質問を編集する必要があります。しかし、これはそのようなケースの1つではありません。

+0

あなたは「役に立たない」という意味を詳しく教えてください。また、インターネットのリクエストから待っている何らかの閉鎖が、常に弱い、あるいは所有されていない自分を必要としていると言うのは公正でしょうか?そして、それらの事実のほとんどすべてにおいて弱い自己であることは間違いないでしょうか? – user172902

+1

'animation'クロージャの弱い参照はユーティリティを提供しません:' animateWithDuration'に供給される 'animation'クロージャは、後で実行される完了ハンドラではありません(別々の' completion'クロージャがありますが、すべて)。これは直ちに呼び出され、アニメーションが開始されますが、クロージャはアニメーションの期間中に「self」への強い参照を保持しません。 – Rob

+1

ネットワーク閉鎖には常に弱い/無所属が必要です。いいえ、これは当てはまりません。たとえば、このクロージャーで何かを実行する必要があるかもしれません(たとえば、ネットワークリクエストの完了に関するローカルDBの更新、ダウンロードしたイメージのキャッシュへの保存など)。クロージャのコードがオブジェクトへの参照を保持する必要はありません(たとえばUIを更新するだけで、キャッシュやデータベース、モデル構造は更新しないなど)。無意識のうちに「弱い」を使用しないでください。クロージャの中身を見て、弱いかどうかを決定します。 – Rob

-1

弱参照

弱参照は、それが参照するインスタンスに強いホールドを保持しない、などの処分からARCを停止しない基準であります参照インスタンス。この動作は、参照が強い参照サイクルの一部にならないようにします。弱い参照は、プロパティまたは変数宣言の前にweakキーワードを置いて指定します。

弱い明瞭さのために、the doc hereを読んでください。

+0

OPは実際に弱い参照が何であるかを知っているようです。しかし、彼は弱い自己について知りたいと思っています。あなたはあなたの答えでは扱いません。だから、これは質問に答えません。 –