I've been profiling one of the apps written in swift lately and been very frustrated with ARC in general, coming from languages where mark-and-sweep GC is the norm.
Especially, UIViewControllers that are very complex with lots of dependencies to other class, I've been failing to get ARC working properly. But I know that simply setting retained objects to nil gets them deallocated without dabbling with ARC.
This is especially true for UIViewController where I can set nil to all retained objects in viewDidDisappear or the similar.
Is this kind of practice considered bad / harmful? Should I just try harder to get ARC working?
edit: By not working, I mostly mean to break Strong Reference Cycle, which becomes quite unwieldy when there are multiple hierarchies of dependencies.
edit: FYI, I'm aware that using weak / unowned in declaration / capture list breaks the retain cycle. I'm asking in cases where using those norms become unwieldy due to the complexity of an object or, rather, the retain cycle of an object.
I think you should take a look at your class structure - basically work out which classes should "own" certain properties (i.e. strong reference) and who just needs to be referencing them when they are available (i.e. weak references).
I think it is well worth thinking about this, as it will probably streamline your code. It will also give you an opportunity to really think about privilege - do all these other classes really need access to these objects etc.
The real problem with setting things to nil is that you have to be sure that you are catching all strong reference cycles and that, ultimately, you are not benefiting from ARC making your life easier.
Try deinit Method its wright way I guess
deinit{
person = nil
}
Related
I am following the last conference of Apple about the GCD on this link:https://developer.apple.com/videos/play/wwdc2016-720/?time=33
I got to the point where it speaks of the precondition here: https://developer.apple.com/videos/play/wwdc2016-720/?time=1267, a new feature in Swift 3.
Arrived at this point: https://developer.apple.com/videos/play/wwdc2016-720/?time=1474 is used this:
.register(observer:, queue:)
my question: how this function retains object BusyController?
https://developer.apple.com/videos/play/wwdc2016/720/?time=1550
You ask how this register(observer:queue:) retains BusyController.
First, let's step back: Let's not get lost in the details of his example. He's not saying that it will establish a strong reference, merely that it could, and therefore you should be cautious about just trying to clean up in deinit.
So, how could DataTransform retain BusyController? It simply could maintain a strong reference to its observer. Note, do not conflate this custom register method example with the standard observer methods: They're just saying "imagine that the DataTransform object established a strong reference to BusyController..."
But, as he goes on to say "but you're skilled developers, and you know how to fix this problem; use a weak reference." So, generally, we wouldn't write observation methods that maintained strong references to their observers.
But, as he goes on to say, even if you're good about avoiding strong reference cycles, the object graph can get pretty complicated, so it's not always a good idea to rely upon deinit to clean up. He's advocating for an explicit invalidate process, and possibly using preconditions to test that the object has been invalidated by the time deinit is called.
As far as i know the weak reference of swift is used because if the object gets nil and you call a method from it, it won't crash your application and just gets ignored. But isn't it a bad practice to allow some of your code to call a function on a not existing object of a class? Wouldn't it be cleaner to just avoid this scenario with good code?
Example what i mean:
weak var manager: MyManager?
manager.someFunction()
Now if the manger object is nil it just won't get called. I know it has it's easy to write code like this but is it really the best practice?
Sorry if this questions was asked before, but i only found explanations of weak and strong. I ask this because a friend of mine told me to use the weak reference to avoid an error call and i think that this is not the best way to handle nil objects because it seems like dirty code to me.
You have been given some misguided information.
Weak is not about making safe calls, but avoiding strong cycles between object instances that will cause memory leaks.
Safe calls are done with optional chaining.
var manager: MyManager?
manager?.someFunction() // this will not raise error if manager is nil
manager!.someFunction() // this raise error if manager is nil
The main point is that using weak communicates something about ownership. It's also frequently used to prevent retain cycles.
That it nils out automatically is useful for some patterns like observing.
Calling methods on nil is a somewhat different topic, which often comes convenient and allows for cleaner (less cluttered, easier to read) code.
For doing more complex logic, you often assign the weak variable into a strong one, so that you can be sure that the whole code runs as you expect it to, and not suddenly works with nil in half the code.
In a non ARC Objective C environment, I understand why we have to release an object: to free the memory allocated for it; I understand why we have to set it to nil afterwards (if we are sure nothing else needs the instance / nothing else still has a hold on the object): to avoid dangling pointers.
However my question is, if all objects release their hold on an object, "carInstance" for example, resulting in its reference count going down to 0, why oh why does that Not automatically make it nil?
If reference count is now 0, is the object still usable in any way? Or is this just one of those things we have to do just because that's how not having garbage collection works (can't be, there must be a reason)
The simple answer is that the manual memory management model that was used pre-ARC is lightweight and simple. The behavior you are wishing for is the behavior you get with weak pointers under ARC; and it requires extra work by the OS, to track weak pointers and nil them out when the object is reclaimed. It's doable, clearly, but the cost of implementing it, as well as the computational overhead, wasn't deemed worthwhile until Apple was already rolling out the extra work of implementing ARC.
After an object is deallocated, the dangling pointer is worse than useless: it is downright dangerous. Referencing it while it points to unallocated memory produces an exception; referencing it after it is randomly reassigned to another object or some other memory allocation will typically produce an 'object does not respond to selector' error.
~ Will ARC always release an object the line after the last strong pointer is removed? Or is it undetermined and at some unspecified point in the future it will be released? Similarly, assuming that you don't change anything with your program, will ARC always be the same each time you run and compile your program?
~ How do you deal with handing an object off to other classes? For example, suppose we are creating a Cake object in a Bakery class. This process would probably take a long time and involve many different methods, so it may be reasonable for us to put the cake in a strong property. Now suppose we want to hand this cake object off to a customer. The customer would also probably want to have a strong pointer to it. Is this ok? Having two classes with strong pointers to the same object? Or should we nil out the Bakery's pointer as soon as we hand off?
Your code should be structured so the answer to this doesn't matter - if you want to use an object, keep a pointer to it, don't rely on ARC side effects to keep it around :) And these side effects might change with different compilers.
Two strong pointers is absolutely fine. ARC will only release the object when both pointers are pointing to something else (or nothing!)
ARC will implement the proper retains and releases at compile time. It will not behave any different than if you put them in there yourself so it will always do the same compilation and to answer your question should always behave the same. But that said it does not mean that your object will always be released immediately after the pointer is removed. Because you never call dealloc directly in any form of objective C you are only telling it that there is no reference count and that it is safe to release. This usually means that it will be released right away though.
If you pass an object from one class to another and the receiving class has a strong property associated with it and the class that passes it off eventually nils its pointer it will still have a reference count of at least 1 and will be fine.
Ok, first this answer might helpt you also a little bit: ARC equivalent of autorelease?
Generally after the last strong variable is nilled, the object is released immediately. If you store it in a property, you can nil the property, assign it to something like __strong Foo *temp = self.bar; before you nil, and return that local __strong variable (although arc normally detects the return, and inferes the __strong byitself).
Some more details on that: Handling Pointer-to-Pointer Ownership Issues in ARC
DeanWombourne's answer is correct; but to add to (1).
In particular, the compiler may significantly re-order statements as a part of optimization. While method calls will always occur in the order written in code (because any method call may have side effects), any atomic expression may be re-ordered by the compiler as long as that re-order doesn't impact behavior. Same thing goes for local variable re-use, etc...
Thus, the ARC compiler will guarantee that a pointer is valid for as long as it is needed, no more. But there is no guarantee when the pointed to object might be released other than that it isn't going to happen beyond the scope of declaration. There is also no guarantee that object A is released before B simply because A is declared and last used before B.
IN other words, as long as you write your code without relying on side effects and race conditions, it should all just work.
Please keep you code proper as it has diffrent behaviour on diffrent complier.
I'd like a critique of the following method I use to create objects:
In the interface file:
MyClass * _anObject;
...
#property (retain, nonatomic) MyClass * anObject;
In the implementation file:
#property anObject = _anObject
so far, so simple. Now let's override the default getter:
(MyClass *) anObject {
if(_anObject == nil) {
self.anObject = [[MyClass alloc] init];
[_anObject dowWhateverInitAction];
}
return _anObject;
}
EDIT:
My original question was about creating the object only (instead of the whole life-cycle), but I'm adding the following so that it doesn't through off anyone:
- (void) dealloc {
self.anObject = nil;
}
/EDIT
The main point of the exercise is that setter is used inside the getter. I've used it for all kind of objects (ViewController, myriad other types, etc.) The advantage I get is:
An object is created only when needed. It makes the app pretty fast
(for example, there are 6-7 views in an app, only one gets created in
the beginning).
I don't have to worry about creating an object before it's used... it happens automatically.
I don't have to worry about where the object will be needed the first time... I can just access the object as if it were already there and if it were not, it just gets created fresh.
Questions:
Does it happen to be an established pattern?
Do you see any drawbacks of doing this?
This pattern is quite commonly used as a lazy-loading technique, whereby the object is only created when first requested.
There could be a drawback to this approach if the object being created lazily takes a fair amount of computation to create, and is requested in a time-critical situation (in which case, it doesn't make sense to use this technique). However I would say that this is a reasonable enough thing to do should the object be quick to create.
The only thing wrong with your implementation (assuming you’re not using ARC yet) is that you’ve got a memory leak—using the setter means that your MyClass instance is getting over-retained. You should either release or autorelease _anObject after that initialization, or assign its value directly instead of calling the setter.
Aside from that, this is totally fine, and it’s a good pattern to follow when the MyClass is an object that isn’t necessarily needed right away and can be recreated easily: your response to memory warnings can include a self.anObject = nil to free up the instance’s memory.
It looks like a decent lazy initialization. Philosophically, one can argue that the drawback is that a getter has a side effect. But the side effect is not visible outside and it is kind of an established pattern.
Lazy instantiation is an established pattern, and it is used by Apple in their (terrible) Core Data templates.
The main drawback is that it is overly complex and often unnecessary. I've lost count of the number of times I've seen this where it would make more sense to simply instantiate the objects when the parent object is initialised.
If a simple solution is just as good, go with the simpler solution. Is there are particular reason why you can't instantiate these objects when the parent object is initialised? Perhaps the child objects take up a lot of memory and are only rarely accessed? Does it take a significant amount of time to create the object and you are initialising your parent object in a time-sensitive section of your application? Then feel free to use lazy instantiation. But for the most part, you should prefer the simpler approach.
It's also not thread-safe.
Regarding your advantages:
An object is created only when needed. It makes the app pretty fast (for example, there are 6-7 views in an app, only one gets created in the beginning).
Are you referring to views or view controllers? Your statement doesn't really make sense with views. I don't normally find myself needing to store view controllers in instance variables/properties at all, I instantiate them when I need to switch to them and push them onto the navigation stack, then pop them off when I'm done.
Have you tried your app without using this pattern? Conjecture about performance is often wrong.
I don't have to worry about creating an object before it's used... it happens automatically.
No, now you have to worry about writing a special getter instead. This is more complex and prone to mistakes than simple instantiation. It also makes your application logic and performance more difficult to understand and reason about.
I don't have to worry about where the object will be needed the first time... I can just access the object as if it were already there and if it were not, it just gets created fresh.
You don't have to worry about that when you instantiate it during your parent object's initialisation.
Yes this is an established pattern. I often use lazy instantiation like this as an alternative to cluttering up -init or -viewDidLoad with a bunch of setup code. I would assign the value to the instance variable instead of using the synthesized setter in the event that this object ends up being created as a result of something happening in -init.