2016-08-21 3 views
7

ARC 및 약점/비 소유 자체 (Shall we always use [unowned self] inside closure in Swift)에 대한 stackoverflow 및 사과 설명서에 대한 조사를 수행했습니다. 나는 강력한 참조주기와 메모리 누출을 일으키는 좋은 방법에 대한 기본 아이디어를 얻는다. 그러나 나는 클로저에서 Weak/Unowned self를 사용할 때 주위를 두려워하고있다. 오히려 "이론"에 들어가기 전에, 나는 누군가가 내가 가진 밑의 3 가지 경우에 대해 친절하게 설명 할 수 있다면 정말 도움이 될 것이라고 생각한다. 내 질문은 약한 자기 폐쇄 및 결과 예제

  1. 이 확인 그들 (내가 무엇을 넣으면, 내가있는 UIView 그러나? 자기와 연관되지 않은 어딘가에 보았 기 때문에 필요가없는 경우 두 가지에 대한 생각의 모든 약한 자기를 넣어하는 것입니다 약한 자아가 있다면 두통을 일으킬 수있는 것이 무엇입니까?

  2. 대답이 '아니오'라고 대답하면 세 가지 경우 모두 약한 자기를 넣을 수 없습니다. 예를 들어 대답하면 크게 좋아할 것입니다. .. 예를 들어,이 VC 때 .... 프로그램이 충돌합니다.

  3. 이것은 weakSelf를 사용하려고하는 방법입니다. 클로저 외부에서 약한 var weakSelf = self를 입력했습니다. 그런 다음 closure의 모든 자체를 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는 인터넷 상태를 확인할 때 완료 블록 내에서 코드를 실행하려고 시도하기 때문에 자체가 더 이상 존재하지 않으므로 아무 것도하지 않습니다 (크래시 없음). 그리고 일단 코드가 클로저 안의 마지막 라인에 도달하면, self에 대한 강한 참조가 파괴되어 VC가 할당 해제됩니까?

그래서 단지 (그것을 시도하고 실행하는 데 반대하고 아무 일도 발생하지 않기 때문에) 더 연습하지만 하나 내 손에 아무런 문제 방법

을 의미하는 그 라인을 무시하는 것이라고 엑스 코드를 의미하는 경우 [약한 자기를] 퍼팅

답변

13

"약한 참조를 사용할 수 있습니까?"라는 질문보다는 "약한 참조를 사용해야합니까"라는 질문을 사용하십시오. 약한 참조를 사용하여 강력한 참조주기를 피하거나 처리가 중단 된 후 닫히지 않도록합니다. 그러나 당신은 수 있기 때문에 약한 참조를 추가하지 마십시오. 경우 1에서

  1. , 당신은 아마 [weak self]를 사용하려면 않습니다. 왜? 권한 부여가 진행되는 동안보기 컨트롤러가 닫히면 정말로 닫은보기 컨트롤러에 대한 참조를 유지하고 싶습니까? 아마도이 경우에는 아닙니다.

  2. 이론적으로 animation 블록에서 [weak self]을 사용할 수 있지만 그 이유는 무엇입니까? 이유가 없습니다.약한 참조는 완료 핸들러 및/또는 클로저 변수로 수행하는 작업이지만, 애니메이션 블록의 경우 유틸리티가 제공되지 않으므로 여기서는 수행하지 않습니다. 여기서 weak을 사용하면 관련된 메모리 의미에 대한 오해가 있음을 나타냅니다.

  3. 경우 3의 경우 두 가지 문제가 있습니다. 객체의 자신의 폐쇄 자체를 참조하기 때문에 아마 [unowned self]를 사용해야 didSelectItemAtIndexHandler에서

    • .

      실제로는 BTNavigationDropdownMenu을 사용하는 것을 볼 수 없으므로 문제가 될 수 있습니다 (이니셜 라이저가 탐색 컨트롤러에 자체를 추가하고 있지만 IMHO가있는 경우 잘 설계된 이니셜러가 아닙니다).

      그러나 일반적으로 객체가 여전히 주변에있을 때만 호출 될 수 있지만 그 자체는 객체를 유지시키지 않아야하는 핸들러 클로저가있는 경우 [unowned self]을 사용합니다.

    • 더 넓은 범위에서 checkUserLoggedIn 클로저의 문제는 이것이 완료 처리기인지 여부입니다. 그렇다면 을 사용해야합니다. 이는 self이 해제 될 때 시작되고 실행될 수 있으며, 해제 된보기 컨트롤러에 대한 참조를 계속 유지하려고하지 않으려 고합니다. 그러나 클로저가 실행될 때까지 해제 되었다면 포인터가 매달려 있기 때문에 [unowned self]을 사용하고 싶지는 않을 것입니다. AS를

      옆으로, 당신은 명상 : 조금 unswifty입니다

      weak var weakSelf = self 
      

      합니다. checkUserLoggedIn 클로저의 시작 부분에 [weak self] 패턴을 사용합니다. weak var weakSelf = ...을 사용하려는 유혹의 예가 있으면 해당 패턴을 사용하려는 위치의 예를 포함하여 질문을 편집해야합니다. 그러나 이것은 그러한 경우 중 하나가 아닙니다.

+0

"유틸리티를 제공하지 않음"이란 의미를 상세히 설명해 주시겠습니까? 또한 인터넷 요청에서 대기하는 모든 종결과 관련된 폐쇄는 항상 약하거나 소유되지 않은 자기가 필요하다고 말하는 것이 합리적입니까? 그리고 거의 모든 경우에 약한 자아가된다는 것이 맞습니까? – user172902

+1

'animation' 클로저의 weak 참조가 유틸리티를 제공하지 않음 :'animateWithDuration'에 제공된'animation' 클로저가 나중에 실행되는 완료 핸들러가 아닙니다 (별도의'completion' 클로저가 있지만 이것은 왁스의 별도 공입니다 전부). 즉각적으로 호출되고 애니메이션이 시작되지만 클로저는 애니메이션 기간 동안 'self'에 대한 강력한 참조를 유지하지 않습니다. – Rob

+1

다시 네트워크 폐쇄는 항상 약점/미 소유가 필요합니다. 아니요, 그렇지 않습니다.예를 들어,이 클로저에서 실행해야 할 작업 (예 : 네트워크 요청 완료와 관련된 로컬 db 업데이트, 다운로드 한 이미지를 캐시에 저장하는 작업 등)을 수행 할 수 있습니다. 클로저에있는 코드가 객체에 대한 참조를 유지할 필요가 없으면 (예 : UI 만 업데이트하고 있지만 캐시 또는 데이터베이스 또는 모델 구조는 업데이트하지 않음) 약점을 사용하십시오. 어리석게도 약한 것을 사용하지 마십시오. 클로저에있는 것을보고 약해 지거나 그렇지 않아야하는지 결정하십시오. – Rob

-1

약한 참조

약한 참조 그것이 폐기에서 ARC를 멈추지 않도록 지칭하고, 인스턴스에 강한 붙잡아 않는 기준 인 참조 된 인스턴스. 이 동작은 참조가 강력한 참조주기의 일부가되지 않도록합니다. weak 키워드를 속성 또는 변수 선언 앞에 두어 약한 참조를 나타냅니다.

약점을 명확히하기 위해 the doc here을 읽으십시오.

+0

OP는 실제로 약한 참조가 무엇인지 알 것입니다. 그러나 그는 당신이 당신의 대답에서 다루지 않는 약한 자아를 알고 싶어합니다. 그래서 이것은 질문에 대답하지 않습니다. –