I did a study on stackoverflow and apple documentation on ARC and Weak / Unowned ( Should we always use [unowned self] inside closure in Swift ). I get the basic idea of a strong reference loop and, as it is not good, as they cause memory leaks. However, I try to get hold of my head when I need to use Weak / Unowned self in closure. Instead of going into “theory,” I think it would really help if someone could kindly explain them in terms of the bottom three cases that I have. My questions
Is it possible to put a weak self in all of them (I think that for the second case there is no need, because I saw somewhere that the UIView is not connected with itself?). However, what if I put the weak I am there, is there anything that can cause me a headache?
Tell me if there is a “No” answer, you cannot put a weak “I” in all three cases, what happens if I do this (for example, the answer would be very appreciated ... For example, the program will crash when this VC ....
This is how I plan to use weakSelf Outside of closure, I set the weak var weakSelf = self Then replace all the "I" in the closure with "weak"? Is this ok to do?
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() } }
- Update-- Most of my code looks like case 3, where everything closes in a closure that either checks if there is an Internet connection before any action is performed. So, could I have a weak body all over the world?
- 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") } }
Question about case 4. Am I saying correctly that even if this closure does not have a weak / unoccupied self, it will never create a strong link (and memory leak), because even if VC is fired before the completion block is completed, Xcode will try run the code inside the completion block when we have confirmed the status of the Internet and will not do anything (without failures), because it itself no longer exists. And as soon as the code reaches the last line inside the closure, the strong reference to the ego will be destroyed, which means it will free VC?
So the old [weak self] in this case would simply mean that xcode would ignore these lines (how to resist trying to start it and nothing would happen), which would mean best practice, but no problem on my arm anyway
closures automatic-ref-counting swift
user172902
source share