Resolving Retain Cycles
Tinder Firestore Swipe and Match
Building applications that are clean and have small memory footprint is a necessity for iOS development. If you have a lot of retain cycles or memory related issues, there's a good chance that you'll experience either early terminations or unexpected behavior with your code. To solve these problems, I'll first show you how to identify issues by overriding deinit. Then we'll look at removing the firebase snapshot retain cycle, as well as other problems. Enjoy.

Comments (16)
cofvco
4 years ago
Hey Brian, I cannot watch this episode!
Brian Voong
4 years ago
Brian Voong
4 years ago
jtcreed@outlook.com
4 years ago
Very Interesting! Thanks Brian
Shaq Noir
4 years ago
Amazing series Brian, glad to have got this far ! Regarding LBTATools, how could I place my collectionView inside another view but still keep the original horizontal scrolling and dimensions ? I have taken time to figure out a bunch of stuff in LBTA but still struggling to get my head around this - I want to do this so that I can have a different colour and corner radius than my 'new matches' and 'messages' headings :) All the best !
romulusc
4 years ago
Enjoyed it, great stuff, learned something new at the end, never dealt with before, the retain cycles memory issues. Thanks Brian. Maybe suggestion for a further lesson, if you have the will and time, would be Notifications on the phone when receving a new message maybe. Have you covered that in another coure of yours Brian?
Brian Voong
4 years ago
romulusc
4 years ago
Cheers Brian, great news. I’m looking to do the Instagram course and AppleStore next so i’ll let you know when i get there.
nick1234
4 years ago
Hi Brian, I am working on getting user locations and using those to eventually setup a distance query to further filter the users. I know how to get a users coordinates and how to use those coordinates to get a point. This is what I have so far for the function: func distanceBetweenUsers() { let coordinate1 = CLLocationCoordinate2D(latitude: user?.latitude ?? 0.0, longitude: user?.longitude ?? 0.0) let coordinate2 = CLLocationCoordinate2D(latitude: <#T##CLLocationDegrees#>, longitude: <#T##CLLocationDegrees#>) let point = MKMapPoint(coordinate1) let point2 = MKMapPoint(coordinate2) let distanceInMiles = point.distance(to: point2)/1609.34 print(distanceInMiles) } For the first coordinate I just pull from the user model which pulls from firebase where I have the coordinates saved. I am not sure how to pull the person's coordinates whom user 1(coordinate1) would be deciding to swipe on. Would I just do the same thing using: let coordinate2 = CLLocationCoordinate2D(latitude: user?.latitude ?? 0.0, longitude: user?.longitude ?? 0.0) or is there another process I should go through in order to pull the other users coordinates. Not sure if this makes sense but any feedback would be very helpful! Thanks!
jtcreed@outlook.com
3 years ago
This is really interesting.. Did you eventually manage to complete this? I'm currently struggling to setup a distance filter. John
mystklfrets@gmail.com
4 years ago
Thanks for the bonus lessons Mr. Brain! It was unexpected, but really handy material.
李承諴
4 years ago
nice job Brian I was confused that how's the delegate object can cause retain cycle now i'm clear about that thanks!!!
cofvco
4 years ago
Hi Brian, I am working on sending Image/Video feature, I wrote some code to add Message Image to Firestore + Storage database, and I have problem with auto-sizing when sending Image Can you suggest me how can I fix sizing of it?, I have already watch your video https://www.youtube.com/watch?v=FqDVKW9Rn_M&t=650s, but I don't know how to fix it with your technique in sizeForItem function in ChatLogController class Thanks!
kiddstu
4 years ago
Hi Brian, just a quick bug I found and fix. If the database is wiped out and we register a new user, we have an infinite loading loop because of the guard about the swipes data. Old code is print("Swipes:", snapshot?.data() ?? "") guard let data = snapshot?.data() as? [String: Int] else { return } self.swipes = data My fix is self.swipes = snapshot?.data() as? [String: Int] ?? [:] And the it allows continuing with fetching the other users. Thanks for this amazing tutorial.
Cinquain
4 years ago
What a great way to end the course
David Guarino
4 years ago
Brian, Great Course definitely learned a lot....Will be doing it over and over again until I get it!..... Side note on you website: When entering full screen on your videos the user doesn't have the capability of pausing unless they minimize the screen
Brian Voong
4 years ago
archid04
3 years ago
Hi Brian, Great videos. You're like the only proper coach out here for iOS. One question, when I click on a chat, it loads the entire chat from firebase. Is this good practise? I'm sure you didn't have the time to show every little detail and implement every little functionality but I was just wondering. What is the best course of action here? Paginate as we scroll to the top?
David Guarino
3 years ago
We probably could just implement the same blueprint he showed us to paginate on the "refresh" button .....Maybe if you're pretty good you could put a (load more) button at the top of chat view and the function could be to load say the next 8 messages. Hope this helps
MIkeb
3 years ago
Brian - amazing course. I discovered a bit of a bug that I can't seem to fix....It has to do with passing in the last fetched uid while ordering by age in the query. The final code for fetching users looks like this: var lastFetchedUser: User? fileprivate func fetchUsersFromFirestore() { let minAge = user?.minSeekingAge ?? SettingsController.defaultMinSeekingAge let maxAge = user?.maxSeekingAge ?? SettingsController.defaultMaxSeekingAge let query = Firestore.firestore().collection("users").whereField("age", isGreaterThanOrEqualTo: minAge).whereField("age", isLessThanOrEqualTo: maxAge).limit(to: 2) topCardView = nil query.getDocuments { (snapshot, err) in self.hud.dismiss() if let err = err { print("Failed to fetch users:", err) return } // we are going to set up the nextCardView relationship for all cards somehow? // Linked List var previousCardView: CardView? snapshot?.documents.forEach({ (documentSnapshot) in let userDictionary = documentSnapshot.data() let user = User(dictionary: userDictionary) self.users[user.uid ?? ""] = user print(userDictionary) print("last fetcehed user is \(self.lastFetchedUser?.uid ?? "")") let isNotCurrentUser = user.uid != Auth.auth().currentUser?.uid // let hasNotSwipedBefore = self.swipes[user.uid!] == nil let hasNotSwipedBefore = true if isNotCurrentUser && hasNotSwipedBefore { let cardView = self.setupCardFromUser(user: user) previousCardView?.nextCardView = cardView previousCardView = cardView if self.topCardView == nil { self.topCardView = cardView } } }) } } The issue is that if you refresh the cards (I changed the limit to 2) .....the var lastFetchedUser is not being passed into the query...so when you refresh it will always pull the same first two cards over and over. When I ty to insert into the query...... start(after: [lastFetchedUser?.uid ?? ""]), I get the error, " You are trying to start or end a query using more values than were specified in the order by" I have also tried creating a query that orders by age first and then by uid and then starts after UID but it does not seem to work... thoughts?
MIkeb
3 years ago
Brian - one thing I am really struggling with is the finished project and how the query is performed in Firestore. Your version does not tie in how to make lastFetched User with also the query for searching by age. The issue is that if you query by age you have to use that in Firebase as the first order by....fore example this code works fine: let query = Firestore.firestore().collection("users").whereField("age", isGreaterThanOrEqualTo: minAge).whereField("age", isLessThanOrEqualTo: maxAge).limit(to: 2) but this will not work: let query = Firestore.firestore().collection("users").whereField("age", isGreaterThanOrEqualTo: minAge).whereField("age", isLessThanOrEqualTo: maxAge).order(by: "age").order(by: "uid).start(after: [lastFetchedUser?.uid ?? ""]).limit(to: 2) I need to figure out how to construct the query so that it meets the firebase requirement of first sorting by age but then also sorts by uid so I can use that to be the starting point for my last fetched user when you hit the paginate button it is not pulling up the same users. I have done a ton of SO and internet search on this but cant seem to find the answer. Can you help with this?
aymather
3 years ago
Hey brian, I can't get this video to load. It looks like I'm getting some errors in the console from vimeo you might want to check out. A cookie associated with a cross-site resource at http://vimeo.com/ was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.
antoinenei
2 years ago
Hey Brian, Thanks again for the great course. Have you considered creating a slack channel for your users? I think that could be a really good addition. You should checkout fireship.io 's slack channel. Its vibrant
HELP & SUPPORT