CHUCK:
Hey everybody and welcome to iPhreaks Episode 2. This week on our panel we have, Ben Scheirman.
BEN:
Hello from Houston!
CHUCK:
We also have Rod Schmidt.
ROD:
Hello from Salt Lake City!
CHUCK:
And I'm Charles Max Wood from devchat.tv. This week we're going to be talking about “Memory Management” in iOS.
BEN:
Scary.
CHUCK:
Yeah! [Ben laughs]
CHUCK:
I understand that it's a lot easier now because you just turned on the Automatic Reference Counter and it takes care of it?
BEN:
Yup! For the most part, a lot of the stuff you needed to know in the past is handled for you, but that doesn't really obviate the need to know; you still need to know how it works.
ROD:
And you may still run an open source code that's using the old way and you got to understand bridging if you're using CoreFoundation, etcetera.
CHUCK:
Yeah. The other thing I understand about Automatic Reference Counting is that it doesn't just magically do the releases and stuff; it actually just, when you compile it, inserts them into your code.
BEN:
Right. There's a fundamental difference between “reference counting” and “garbage collection”. Garbage collection is certainly handier from a development perspective; you don't really have to think about it too much, you just stop pointing to objects and they'll get collected later on.
Unfortunately, it has some unpredictable performance implications especially on an embedded device, so Apple has chosen to go to completely deprecate garbage collection and it was never possible to do that on the iPhone. So, you'd have to manage your own memory and do reference counting. That means, when you create an object do a reference to it, then you need to call release later on. And if you didn't create the object but somebody else, say, retrude this object via method call or something else, and you wanted it to stick around for the lifecycle of your object, you would have to call retain on it. And of course, anything that you retained, you will also have to release. So it was a little bit scary for me first coming into Objective-C just because I hadn't done C in a long time, and you have the same problem with C where you malloc and you free memory. So anyway, it turned out to not be that big of a deal, honestly. Once you follow the rules, it just becomes second nature.
CHUCK:
Yeah. Let me back up just a little bit and explain what we're talking about here. So garbage collection, basically what happens is you tell the -- well the three programming language -- is tell the operating system to allocate a certain amount of memory for your object. And then when you're done and the object goes out of scope -- and in most cases this is automatic with the higher level languages -- but anyway, when the object goes out of scope, then there's a process or a thread that comes through and cleans up anything that is out of scope and therefore isn't being used anymore. The problem is this, the garbage collection algorithms aren't always the most efficient and sometimes there are other side-effects to the way that they work. With reference counting what happens is, when you call retain in iOS, for example, it basically says now there are two places that are saying that they care about this object. And then you call retain again and it goes to three; and then when you call release, then it goes back down to two; and when it goes back down to zero, then it clears it out of memory. Is that more or less the way that it works?
BEN:
Yup!
ROD:
Yeah!
BEN:
And if you get it wrong, one of two things will happen: you either over-retain or you over-release. The first problem is harder to debug because your app will still work; you're just keeping on to memory for a lot longer than you should and that memory will never get cleaned up until your application gets killed. The other problem is if you over-release, it will crash right then and there because your objects go away when you still expect them to be there. So, your program crashes and then you fix it.
ROD:
Yeah.
BEN:
So it's easier to get it wrong where you over-retain.
CHUCK:
And for people who are newer to programming, when you hold on to an object that you no longer need and you do this frequently enough, we call this a “memory leak”. Basically, the concern there is that as you pile more and more stuff up in the memory, eventually you will run out. And then when you try and allocate something else in the memory and you don't have anymore space for it, then whatever programming is trying to allocate that may crash, or hang, or both.
BEN:
Yeah. So on the iOS, if the device is slow on memory and your program needs memory, then it will tell other applications that “We’re receiving a Memory Warning”. And if they have a chance to release things that they're hanging on to, they could easily create again. So like if you are holding on to some kind of contents from a filing disc in memory as a dictionary or something and then you got that Memory Warning, you could just release that object. And then next time, if you did load, gets cold, or whatever, you could just breed it from disc again. So it gives you an opportunity to free up stuff in the case of memory pressure.
CHUCK:
So, do you write that kind of thing into your programs? Where, if you get a request from another program that says "We're getting a Memory Warning", you tell it what kinds of things that come at go.
BEN:
Yeah. This used to be super important. When the devices didn't have very much memory, all the time, we'd get this Memory Warning. So, we change the behavior or application because either the program will crash because it just can't allocate enough memory, or we wouldn't do it correctly, like if you release something that you expect to be around later. Couple of years ago this was paramount important, Nowadays, it's a little bit easier to be lazy and not release memory just because the devices have more of it.
ROD:
I tried to do it with like temporary optics like Images or even Views that you'd crack and reload or whatever. But like Ben said, nowadays, you don't have to worry too much about it.
BEN:
Yeah, and it really influences your design. So if there's something that you have that's somewhat expensive to create and you create that thing -- let's say you created it in like a viewDidLoad -- so later on, if you remove it in the Memory Warning, you have to make sure that that thing gets created again. So, extracting the initialization of that object somewhere else so that you can call it multiple times can be handy, but I think even better is to use “Lazy Initialization”. So, you declare this object as a property and then you override the getter of the property and you check to see if you're backing instance variable snail first. And if it's nil, then you go ahead and create it and return it. By doing that anywhere in your program, like in the didReceiveMemoryWarning block, you can snail out those things and then they'll get recreated next time they're accessed. So, you don't have to worry about the view lifecycle or anything like that.
CHUCK:
That's a handy trick!
ROD:
Yeah, and it works really well.
CHUCK:
Now, is that something that most people do? Or is that just a trick that you guys are kind of come to on your own?
BEN:
That's a good question. We do it on my team, but now it's just because we're all talking about you have to write software better, write us and we all share ideas. I think that's, in general, pretty good design, though. Extract things, do lazy initialization -- well-factored Objective-C code doesn't kind of resembles well-factored Ruby code, in my opinion -- so I do the same type of thing in Ruby. When refactoring, just extract methods so that when you create something it nil assigns it into a variable or whatever; it makes it really easy to extract known concepts of your code.
CHUCK:
That makes sense. I kind of wanted to ask another question really quickly, and that was: I remember back in the battle days when I was writing C in college, sometimes you would malloc something and then you would move through several different scopes and then it was hard to find a reference to the object in order to free it. Do you ever ran into the same kind of thing with retain and release?
BEN:
You always have a pointer to it, right? See there are an ivar, or to a local variable, or it's a property; it seems like you always have a reference to that object.
CHUCK:
Yeah. The more I think about it, the more I realize that I probably just had poorly written my code and I needed to basically free it at the last point that I had a reference to it.
BEN:
Right.
ROD:
I remember my old feed days and there are much more memory calling to it free and malloc then there ever was, but released and retained in Objective-C.
BEN:
Yeah, one of the problems like even with C is, you have a lot of functions that create stuff for you. So when you're handed back the object, you have to own it. So having that malloc happen in one place and free happen in another seems very unbalanced.
CHUCK:
Yes.
BEN:
In Objective-C, the rules are: if you alloc or init, new, or copy something -- so if the method you're calling to create it starts with init, new or copy, then you own the retain count and you're responsible for releasing it. But if you retrude that through any other means like the factory method I just mentioned, the Lazy Initialize property, that object does not belong to you and it is known to be autoreleased, which I like as a pattern in general because it allows me to just call a method, extract the creation of some stuff into a method and have that method returned, and I don't need to be worry about releasing it. To do that, I have to call auto-release just before returning from the method. So, that does it as the object to autorelease pool. And on the next clock cycle or on the next run loop, rather, it will drain the autorelease pool and release all the objects. So it's like a temporary that said "Release this later", and the calling code has a chance to retain it again themselves if they want it to stay around. But usually, you just use the object and continue on.
CHUCK:
So these are kind of short-lived objects that you only need for, say, one iteration of your method or whatever?
BEN:
Yeah. And if I needed it to stay around, then I just say "retain". Or, more and more common these days is to use properties in your implementation file in the class continuation at the top; it's the way to declare private properties. And if you mark the property as retain and pre-ARC days, and strong and ARC days, then you don't have to worry about retaining it; you just set the pointer and it handles the Memory Management for you and later on you just have to set it to nil to release it.
CHUCK:
So once you've fully released an object, does it immediately remove it from memory? Or, is there some kind of garbage collection on the back end that you just don't have any visibility into?
BEN:
You could watch this happen; you could set a break point in dealloc and watch when it gets called. So as soon as your retain count goes to zero, meaning you've released the last reference to the object, dealloc gets called right then and there. So you have a lot more control over -- like object allocation and deallocation takes time and if you really do this and its run loop, you'd start to notice it, affecting performance. So if you just moved your last release somewhere else, you can actually see what that does to your memory profile and how it affects the CPU.
CHUCK:
Oh, interesting.
BEN:
So one of the ways you would see this happen, like in game development since you have basically 16 milliseconds to completely do all updates in your game and redraw everything in order to finish and draw the scene so that the next time you draw it again, you're running at 60 frames per second - so you have, I think, it's 16.7 milliseconds. So if allocating 10 or 20 or 100 objects take some of that time, you're going to really care about its performance. And you might now think that that's so important in business apps except on the iPhone; when you're scrolling your Table Views, you can easily get 60 frames a second when scrolling that. And object allocation is really expensive and you'll notice a hiccup, as that happens. So Table View, they introduced the “reuse queue” so you'll only create your cells once for each cell that is visible on the screen. And then they just go into a reused queue when they go off-screen, and the one that just comes on the screen is about to be appeared because it's dequeued from that list. So you can see probably 12 rows at a time; you probably will only have 13 total objects in that que. And you can use that to speed through thousands of rose of contents because it's not doing that memory allocation and deallocation while it's trying to animate.
CHUCK:
That makes sense. So, what do you get from ARC then?
ROD:
It's kind of best of both worlds - you have Automatic Memory Management and you have the performance.
CHUCK:
What do you mean? Is it not doing the same thing that --
BEN:
I think you mean best of both worlds with respect to garbage collection and Manual Memory Management, right?
ROD:
Correct. Right.
CHUCK:
So, we said that we don't have garbage collection on iOS?
BEN:
Yeah. So what that does is, I mentioned that there are some rules to retain and release like if I own the object I have to release it. If I don't own the object, I'll only retain it if I wanted to stay around; and if I retain it, then I wouldn't have to release it. So, all these rules became such strict rules that Apple eventually released a static analyzer that you can use. If you hit Command-B to build an Xcode, you hit Command-Shift-B to build and analyze; and the analyzer will tell you where your memory leaks are so that everything it tells you is actionable. You might miss a few edge cases here and there where you can't figure it out, but everything that it tells you, you can act on it and fix a memory leak. So it'd point you and say "Hey, you allocated this object up here and you didn't release it down here, so it would probably won't release you or you probably won’t autorelease here". And because it could do that, they have the smarts to do that, they eventually just base those smarts into the compiler so that when you compile, it just stitches in those retain/release/autorelease where they're needed and you don't really have to think about it. So, I'll slap a huge caveat on there; it's really important that you know what it's doing for you under the hood because this is not garbage collection. So it's still possible to introduce memory leaks and it's still possible to crash; you just have to understand what ARC's doing for you and then you just kind of don't need to write that code.
CHUCK:
So if you find that ARC is doing the wrong thing and causing you memory leaks and what have you, can you still co-release yourself?
BEN:
No, that's a compiler warning, those keywords are removed from the language. I went through a process last year updating a large app from non-ARC to ARC and it was kind of a pain -- actually it's a gigantic pain -- because things like that, you can't just do it overnight. So we maintain to branch where you're slowly but surely converting things over and testing them, and we could turn off, turn ARC on file by file basis using a compiler flag. Once we got it all over, we could turn on ARC for the whole project. And once ARC is on for a file or the whole project, it will start, it will warn you if you call retain or release yourself; and if you implement dealloc, you cannot call super dealloc. So dealloc would just be kind of like a template method that you would use to clean up stuff once your class is going away, but you don't need to call super.
CHUCK:
Huh!
BEN:
Where ARC can get a little bit messed up is not necessarily ARC's fault, it's just a fundamental problem with the way code can be structured in which you get what's called a "Retain Cycles". So if you have a “parent-child object” -- let's just say you're following some good object what I'm practices -- and you're taking this big controller, this big class, you're just composing it into lots of smaller classes. And because I'm using the smaller classes in the parent class -- let's say I'm just delegating some responsibilities to another class but their life cycles are still bound to each other -the child is going to live as long as the parent lives; once the parent goes away, the whole tree should go away. If we do that and we have a reference from the parent to the child, which would be a strong pointer in ARC terms. That means, when you assign an object to that pointer, it will do the retain for you. If the child points back to the parent in a strong fashion also, then you have both objects pointing to each other. So…I'm doing hand motions that you obviously can’t see…[laughs] [Chuck laughs]
BEN:
So you have these things pointing to each other, right? (you could do this of your fingers at home). So when are either of these going to go away? When either of the retain count is good as zero.
CHUCK:
But they both have a retain on each other so it will never happen…
BEN:
Exactly. So, they'll never go to zero. And this happens quite often so you spot those areas where it happens and you say "Oh, that pointer needs to be weak". So in this case, the child's pointer back to the parent needs to be weak so it does not retain the parent. And that allows, once the parents last the retain goes away, then he will get deallocated and he will release all of his objects, in which case, the child will get released. This happens all the time with a delegate pattern, kind of like the UITableView delegate. If you look at the reference to that, it's a weak pointer. The reason is, your Table View is bound to your object or your ViewController or whatever, and you probably also does the delegate for that - delegate and data source. So when you tap on something on the Table View, it notifies its delegate to something happened. And so that delegate pattern is always a weak pointer because you always have some sort of parent-child relationship with that object. These things happen actually in such known areas that you can immediately spot them once you know what's going on.
CHUCK:
Yeah, that makes sense. Are there any gotchas with ARC?
BEN:
Yes, there's a couple of others. I was just talking on Twitter with a guy who's asking about RubyMotion and how RubyMotion deals with this. It seems as if RubyMotion doesn't have to deal with this, but they actually do; it's just doing similar things under the hood. One of the other gotchas I mentioned on Twitter is, you have a "Block". A block is just a closure; it's like an anonymous method that can be invoked at any point in time later on. Because of that, those rules, every object that use inside of the block has to be retained so that they stick around at the time of the block executing. So, it's like the block is retaining the objects inside. So, you can run in this situation where you perform a method and that's going to call the block later when the method is completed so seem like maybe asynch network call. And if you invoke a method on self inside the block, it's going to retain self so you have the block retaining the owning class; so it's again that parent-child relationship. The way you break that retain is by creating a weak version, a weak pointer version of self. That one is a bit confusing; it's done through the __weak pointer qualifier. So basically, you'd say __weak self = like I usually call it "weak self", and then I use the weak self pointer inside the block. So it's basically just creating a new pointer, pointing it to self with the __weak qualifier, and then use the weak self pointer in the block. That informs the block not to retain self.
CHUCK:
So, it's kind of like in JavaScript because you have things that are "closures"; you make it close over something that isn't this keyword, but it's something else that points to what you want. [crosstalk]
BEN:
(In) JavaScript, you can bind this to whatever so it depends on the context in which you invoke that function. In Objective-C, we're just retaining the objects. So if that block is never going to be released, because it's bound to the lifecycle of the class that it was created then. A typical example is notifications; you cannot handle a notification and pass in a block. You typically want to do at -where do you release your notifications? Well, like in the dealloc or in the viewDidUnload or something, basically the notification handler, which is a block, is bound to the lifecycle of View because it's going to stick around for the whole time. So, if you're capturing self inside the block, you're going to retain the parent class and then you have that parent-child strong pointer retain cycle problem.
CHUCK:
Right.
BEN:
So if you add the weak self pointer, which is kind of (let's be honest) it kind of sucks that you have to do this, but it's a small price to pay, for what Rod was just saying, it's like the best of both worlds. There is one last curve ball to this...[laughs] [Chuck laughs]
BEN:
I don't know if this is coming across well with me describing it, but -- so we have declared this variable as weak so that it's not retained inside the block -- but then, we're kind of in a danger state like when the block is executing, if that you control a class did get deallocated while the block is executing, then our accessing self at that point could crash.
CHUCK:
Yeah, I can see that.
BEN:
So what people do, when they finally found these problems out and they're like "Okay, I know what to do", they create a weak pointer outside the block, and then inside the block, they create a strong pointer. And then by the time the block is done executing, it will release its retain on that.
CHUCK:
Oh, so they just create a strong pointer without actually --
BEN:
Inside the block. So weak pointer outside the block, you use it inside the block to create a strong pointer, which does the retain. And then you do your code and strong pointer gets released and --
CHUCK:
Oh, the strong pointer gets released when the block is done executing?
BEN:
Yes.
CHUCK:
Because it's then popped off of the stack and the strong pointer goes out of scope so it's released.
BEN:
Yup! Exactly. So it's, again, it's just this unfortunate aspect of dealing with ARC and Manual Memory Management, but the benefit is you get really fast consistent code and you don't have to worry about the weird performance characteristics of a garbage collector.
CHUCK:
Yeah. And the other thing is, you don't have to remember to release or retain everytime either.
BEN:
Right.
CHUCK:
Interesting!
BEN:
Rod, do you want to talk about dealing with CoreFoundation?
ROD:
Yeah, I'd tell a litte bit about that. “CoreFoundation” is the sea-level API to some of the frameworks that Apple has that Cocoa's built on top of - so it's a C-Based API. They implement some rules that are very similar to Cocoa, so you typically have a function that will create a object or data structure that ends with "copy" or "create". And then to release that, you call like CFRelease. And also, if you want to retain that somebody else wants to retain it, they call CFRetain on the pointer that was returned by that creator "copy function". So say you have what we call "TollFreeBridging", which is some objects, CoreFoundation objects such as arrays, strings, or dictionaries, you can directly cast to the Cocoa equivalent. So a CoreFoundation string, CFString can be cast to an NSString. So with argue run into an issue, who owns that object when you transfer the pointer?
CHUCK:
When you transfer the pointer meaning you cast it from a CFString to an NSString?
ROD:
Right. When you do a TollFreeBridge...So with CoreFoundation, you basically have to do the retain/release management of memory yourself. But --
CHUCK:
So there is no ARC for the CoreFoundation stuff and C?
ROD:
Correct.
CHUCK:
Okay.
ROD:
But, you can't transfer to the TollFreeBridging and transfer it to a Cocoa pointer. For example, there's these cast moth fires, __bridge says (when you do this cast) "Don't transfer the ownership", so you still have to manage that memory yourself, CoreFoundation owns it, you have to release it whatever when you're done. And there's also __bridge_retain, and that typically is when you're going from the other way, from Cocoa to CoreFoundation. So that transfer is the ownership to CoreFoundation, and then you have to manage the memory yourself. Or, like what we're originally talking about, you're going from a CoreFoundation function object to a Cocoa object, you use __bridge_transfer and that will transfer that CoreFoundation object to ARC, and then ARC will management from there. Now, typically when you're doing this you'll get compiler warnings and Xcode will pop up the thing telling you how can fix it, suggest one of these keywords cast modifiers. Did I get everything, Ben? I think I did.
BEN:
Yup! That covers it.
CHUCK:
That's interesting. I think I forget fairly often that Objective-C is basically C with a bunch of extensions on top of it.
BEN:
The other thing is, Xcode is really good about telling you "Hey, I think you want this here", or at least gives you two choices and you get what's like a little "fix it" window, and you just click on it; it says "Do you want a bridge retain or bridge transfer", or sorry...is that right? [laughs] Anyway, it gives you the options and you're like "Ahh", and then you say "What are those mean?" you go look up the docs and it tells you. So it's not like you're going to ship an app and not know you're having to deal with this problem, Xcode will tell you; you have to pick one, and you pick the most appropriate one.
ROD:
Yeah.
BEN:
With that said, these areas are just kind of French cases like you see them and you notice these patterns and whatever. But 99% of the time, you're just using ARC in the same way you use a language like Ruby or Java or C#; you just write methods that return objects, they get out released. Or you write methods that create objects and use them, and those get released at appropriate time.
CHUCK:
Yeah, that makes sense. So in Xcode, my understanding is that by default on new project, ARC is enabled but you can go in and you can uncheck it and turn it off?
BEN:
Yes. And that really, there's no reason not to use it; if you are working on a newer project, then you should do that. I just think that, there's also age-old debates like "should I learn X when there's this higher level thing?" I definitely think you should learn how to do Manual Memory Management, like just go through 1 or 2 tutorials and learn the rules. And from that point on, you can just use ARC and be happy that you didn't have to suffer through these days of Manual Memory Management.
CHUCK:
[laughs] Yeah.
BEN:
Also really good to talk about, since we're dealing with memory, is the "Instruments" as a fantastic tool for finding leaks in your program.
CHUCK:
Instruments?
BEN:
Yeah. So if you're in Xcode, you just type command "i" which will profile your app with Instruments. And you can choose various types of tools in here -- I'm going to run it so I can tell you what they are -- it's under the product menu, product profile. This will launch your app inside of Instruments and then you get to choose one of these various templates; one of them is called "Leaks". If you run your app with Leaks Instruments, it launches a simulator and it tells you what objects are getting allocated and how many megabytes and that sort of thing. And then you can sort of poke around your application by pushing buttons, which obviously creates objects and releases objects and all kinds of things - go to different ViewControllers, back out of them. At any point in time, if you have a Leak, it will spike and it will tell you what the Leak is. I just did this on an Apple I'm working on I found the Leak. [laughs]
CHUCK:
Nice.
BEN:
So I can go to it and it tells me exactly what the object it was that got leaked. It tells me the memory address and then you can click on it and they'll tell you the lifecycle of what happened. So it looks like I need to look at that, digging to this particular one. But, it's a really good tool and super easy to use. And since it's built in the Xcode, you should definitely take a look and see if you're leaking memory.
ROD:
Another useful tool is "NSZombieEnabled, which is zombies or dead objects that have been released by [inaudible] and send a message to them, so they'd crashes. So there's environment variable called NSZombieEnabled that you can, in Xcode, you can set up the arguments when you run your app and it'll set that to "True", and then it keeps track of all your objects. And if you send a message to a Zombie, it'll tell you about it.
CHUCK:
Oh, that's interesting. Now, this is when you're under in the simulator on Xcode?
ROD:
Yeah. Or, on your device.
CHUCK:
Oh, you can do that, too?
ROD:
Yes.
BEN:
Yeah, you can do that. Just make sure that you turn it off when you not want to use it because what it does (when the object is deallocated), instead of actually releasing it, it hangs around. And it's in a known location that just throws exceptions, saying "Hey, somebody tried to call me and here's the stack trace", just so that you can catch it right then and there. But it also prevents you from never detecting leaks because none of the objects are getting released. So Instruments will tell you that you can't actually detect leaks with zombies enabled so it's just a setting you can turn on and off.
ROD:
Right. And it does really slow your program down so you don't want to keep it in there.
CHUCK:
Right. But it seems like one is a good way of detecting leaks and the other is a good way of detecting when you over-released and your app is blowing up because you're trying to talk to someone who's no longer should be there.
ROD:
Right.
BEN:
Another thing, since we use a lot of open source libraries and we bring in third-party code and that sort of stuff in our apps, during this transition of non-ARC to ARC, some of the libraries out there were like "Okay, we're finally making the transition. We're now only using ARC". And for people who pull this stuff end manually, it's kind of a pain because you have to change the compiler flags for each file if it doesn't match your project setting. So if you don't use ARC and this library you want to use does use ARC, then you have to do that. What’s cool about this system called "CocoaPods", which we use for pulling in third-party dependencies, is that the CocoaPod itself declares whether or not the file uses ARC, the project. And so it will automatically add those flags for you when you include it in your project.
CHUCK:
Oh, very nice. If you're pulling them in by hand instead of using CocoaPods, is that really the only way to do it is to set the compile flags profile?
BEN:
Yeah. If they don't match your setting, yup! I think, there is something that I saw in one of these holder projects where somebody is trying to get around it by providing one library that worked in both environments and you had to do some sort of compiler to find and it would redefine release to do nothing. Stuff like that is weird; just doesn't seem like a good solution.
CHUCK:
Yeah. I can definitely see that. Changing something especially keyword is to find for the language...Yeah, I can see why that might cause a problem - if you're calling it somewhere else, expecting it to do something.
ROD:
I guess one of the things that didn't mention is the "AutoReleasePool" keyword that's for ARC - the new keyword they introduced. In the old retain/release method, there was an autorelease not that we talked about. In ARC, that'll do that. However, if you do have a tight loop or you're allocating one objects and you will free them up sooner than that you can use this autorelease block kind of, so you say autorelease [put your code], and then you'll have autorelease pool in that section of code.
CHUCK:
Huh! That's interesting. And so it will just autoreleases anything that's allocated inside of that block?
ROD:
Yup!
BEN:
Yeah, it does that. I don't think I've ever really had to use this outside of when you used to have to create your own threads. So like on autorelease pool, there's one given to you. You can look in your main.end and you'll see it. Basically, it just means that under the next run loop, it will clean up all those things to get in that spot. So if you're in a tight loop, like Rod was saying, if you created thousands of objects and they're all autoreleased, and you're looping over that creating many more thousands of objects, you probably want to start freeing those things up incrementally, rather than all at the end. But again, autorelease is such a tiny tiny performance set that it's -- I don't know how relevant it is anymore to need to use autorelease pools yourself. What do you think, Rod? Do you ever use that anymore?
ROD:
Not anymore. I remember in the old way, I had to use it a couple of times. But yes, when you're allocating a ton of objects and it's affecting the performance, then you might want to look at it.
BEN:
Yeah. Used to be, when we needed to do multi-threaded code, you'd actually say "Perform this selector and background", which would create a threading call, a method on it. In that method, since you're running on the background thread, you couldn't create any objects; it would say "You need a new autorelease pool on this thread". And so you'd have to create an NSAutoReleasePool and then drain it at the very end.
ROD:
Right.
BEN:
Now that code is deprecated in favor of this nice "@autoreleasepool" block.
CHUCK:
Alright. Cool! It was just really interesting. I got a whole lot more out of that [laughs] than I thought I might get! [Rod laughs]
CHUCK:
Are there any other things that we need to talk about with Memory Management?
ROD:
Do we need to talk about the properties and how you specify them?
BEN:
Ah yeah, we didn't talk about Weak, what ARC brings for Weak Pointers either.
CHUCK:
Go ahead.
ROD:
Right.
BEN:
Okay. So before ARC, you had "Retain and Assign" properties. So if you had something that was an object, you would generally use "retain" if you wanted it to be retained. Or, if you had like an image or a float, or a bool, you'd use "assign". In the third case, we have a delegate where you do not want to retain the pointer back to the parent, you'd use assign there as well so that no retain would happen. The problem with that is this, once that object that you're pointing to goes away, then memory is no man's land; it could be some other object so you'd get these weirders like "Hey, there is no method; start up the Ferrari on NSString", and you'll go like "It's really weird. Why is it looking for that method under the NSString?" That's because some other object is now occupying that memory. Or, more common it just crashes because that memory is just garbage. So with ARC, you now have a pointer qualifier on all these properties. You have "strong", "weak", and "unsafe_unretained". Under unsafe_unretained is the same as pointing to an object with assigned semantics. So no retain happens and if the object goes away, you're in danger. Weak is the same thing except when the object it's deallocated that you're pointing to, that pointer becomes zeroed out, which effectively makes it nil which means anything you call on it becomes a no-op - which is a lot safer than crashing. [laughter]
BEN:
I interview a lot of people and I always ask that question like, what is a weak pointer? A lot of people just think it's a sign in ARC days, but it's really a zeroing weak pointer, which is a really handy thing to have. That was introduced in 4.2, I think. So if you had an app that was using 4.0, you couldn't use it; but I think as a 4.2 and above, it's been around.
CHUCK:
Oh, okay. And then a strong pointer is the retain, we've talked about before that stuff.
BEN:
Yup!
ROD:
There's also variable qualifiers that go around along with that if you don't want to clear property __weak, __strong, __unsafe_retained..
BEN:
That's unsafe_unretained, right?
ROD:
unsafe_unretained. Right. And I've ran a couple of bugs lately with ARC on Lion, and it seems like certain, especially NSWindows, you can't have a weak reference, a weak property reference to a window for some reason you can't create the weak reference. And on Lion, only on Lion, I have to use the assign property type.
CHUCK:
Huh!
BEN:
Were you using a nib?
ROD:
They were typically delegates. So I was using a weak delegate and for some reason, it couldn't create it; it caused crash and I had to switch to assign.
BEN:
I remember when I was reading first book on Cocoa development, it was talking about whether or not you should win declaring outlets for use in interface builder so you could say "Have a reference to a button on your user interface". And you would control-drag (Ctrl+drag) from the button over to your code and you would say "Okay, connect to that with my button property". On iOS, you would have a situation where you could declare those as assign or weak because the nib itself was retaining the objects. But on the Mac, those would cause the objects to get released immediately so you had to use strong. So I remember the advice used to be a couple of years ago, just use strong because you have more consistent code across Mac and iOS. Now, I've seen that they have changed the templates so when you just create an outlet using Xcode and the Assistant Editor, it will create a weak pointer for you. I assume it's the same on the Mac now, right?
ROD:
Well, I think you might have gotten that back results because when I was doing the Mac programming, you set your outlets and you don't have to retain or release the View to single window for [inaudible], so you have a pointer to window because all you have to do the app as the pointers to window; the window is retaining all those gears and everything. And then when iOS came out, there was always strong references to your Views and you had to manage that. And then when ARC came out, they switched it so that you can use weak outlets. That's what I've seen lately.
BEN:
Right. Yeah, that's what I said. I think I said that, anyway.
ROD:
Okay. [laughter]
CHUCK:
Listen to what I meant, not what I said.
BEN:
Yeah [laughs]
CHUCK:
Alright. Well, we're just about at the end of our time. Are there any other aspects of Memory Management that we ought to talk about before we wrap this up?
BEN:
I don't know...It's just not as scary as I thought it was be when I first got into it. So, you just kind of like the guy in the Matrix who's just like "Now if I see blonde, brunette, red head..." it's kind of like you can spot the memory leaks pretty easily because it just looks wrong.
CHUCK:
Yeah. It sounds like there are good tools to help you identify them as well.
BEN:
Yeah.
ROD:
Yeah. And I remember doing Java and even all that garbage collection we've ran into all kinds of memory problems and memory leaks, it wasn't very performant. And then when I went over to Objective C, everything just seemed to work a little bit better now. That probably could be because it's compiled language, but I think the Memory Management was part of that performance as well.
BEN:
Are you ready for the email you're going to get on that comment? [laughter] CHUCK: I was going to point out that Java is compiled and then it's interpreted on the JVM.
ROD:
Right.
CHUCK:
Anyway...Alright well, let's go ahead and get into the picks. Rod, do you want to start this off?
ROD:
I will pick the new service that came out from the CocoaPods guys, "cocoadocs.org", which you can look up the docs or any open source project you think at one place. So, it looks pretty interesting. For my second pick, I'm going to pick my own website, the "getnumerology.com"; it's my first Rails app that I just released to generate numerology that works.
CHUCK:
Awesome! Ben, what are your picks?
BEN:
Okay, so a lot of people come up to me at conferences and they're like "What was that plugin you're using in Xcode?" Xcode has a really horrible plugin system, but that said, people do make plugins for Xcode. The first one I use is "XVim", I'll paste/add links to you so you could add them in the show notes. So XVim gives me vim keybindings in Xcode, so I have 'insert mode', 'command mode', and I can do all the motion keys, and things like that. Occasionally, it causes Xcode to crash, but not enough to make me stop using it; that's maybe like one time a week or something. But I just find that since I use Vim for my Ruby work, that it's nice to just jump in and have the same kind of keystrokes everywhere. The next one is called "OMColorSense". OMColorSense basically, if I start typing [UIColor redColor], it puts a little tab, like a rounded rectangle tab on the top of that line of code with the redColor in it. And if you click on it, it brings up the standard OS X color picker; you can change the color and it changes your type to code to [UIColor colorWithRed : Blue : Green : Alpha]. And so you can tweak that color however much you want and you can even change alpha value and everything, which is pretty awesome. So if you just need to kind of throw some together and you want a color, and obviously you don't want to use red, which you might want to darken it up a little bit, you can just use the color picker and it changes your code for you. The last plugin I use is called "KSImageNamed". That one is kind of in similar vein if I type UIImage ImageNamed, it will bring a popup with all of the images in my project, and I can just use the arrow keys to select one and hit enter, and it will fill it in for me. On my project, I have hundreds of assets so it's nice to be able to have some of them autocomplete.
CHUCK:
Nice. Alright. So my picks, the first I'm going to pick is "Rechargeable Batteries". I know it's not an iPhone programming deal, but it's really really nice for the things that I have. I have bluetooth keyboard and a bluetooth Magic Trackpad, and it's really nice just to be able to swap them out and then you don't have to go buy batteries every so often. So, that's one pick. The other pick that I have is, (I'm trying to remember what this called), it's called SmarFinder, I think. It kind of drops in and replaces Finder, but it gives you, in your Finder window, it gives you tabs, you can also go into a mode where you have two folders side by side that you can just drag across back and forth. I
really really like this thing; it just makes things a whole lot easier for what I do and when I need to move files around of my machine. So, those are my picks. I'll put links in the show notes. And it looks like next week, while we're talking, we're going to talk about next week. So, stay tuned and we'll see you all then!