Objective-C method execution while object is deallocated - should I fix that? - ios

In methodA of my view controller VC1 another view controller's (VC2) method methodB is called in which VC1 is deallocated. Then control returns to VC1 methodA which obviously crashes when self is used.
It is not obvious that the instance is deallocated, so developers may use self without knowing that they should not. From that perspective I'd like to fix the deallocation. However, I'd like to get some opinions whether or not such a situation is common or needs to be fixed ASAP a.s.o.
Q1: Is execution of deallocated object's methods somewhat common which one will encounter in typical medium projects?
Q2: Would it be acceptable, if comments are added, which warn the developer?
Q3: Are there any other recommendations / opinions?
The project is of medium complexity (about 200 classes of which 50 are view controllers). I'd like to get a feeling about how much effort I should invest to take care of such "deallocated method calls". If it would be one of my smaller pet projects, it would be rather easy to fix anything. However, with an inherited project which already went through a couple of hands, things are not so trivial any more.
EDIT:
didFinish delegate scenarios:
Thinking about it, I came across didFinish kind of delegate calls. Assume a master view controller (MasterVC) uses a slave view controller (SlaveVC) to do some work, keeps a strong reference to it and sets itself as a delegate for the SlaveVC. When the slave is finished, it calls slaveVcDidFinish. In MasterVC's implementation of slaveVcDidFinish the strong reference to the SlaveVC is set to nil. So when the slaveVcDidFinish returns, it is SlaveVC's responsibility to never use self, as it may have already been deallocated.
- (void) notifyDelegate
{
[self.delegate slaveVcDidFinish];
// From here on, `self` may be invalid...
}
This likely is relevant, when the SlaveVC is dismissed before the call to slaveVcDidFinish, as otherwise it cannot be deallocated because it is part of the view controller hierarchy.
Q4: Is my understanding of this didFinish scenario correct?
[/EDIT]
A few details, in case it is relevant:
VC2 presents VC1 and keeps a strong reference
VC1 does its work and needs to present VC3 for which it dismisses itself before
VC3 does its work and delegates back to VC1's methodA
VC1's methodA delegates to VC2's methodB
methodB releases the strong reference to VC1, VC1 now gets deallocated (dealloc is called), and control returns to methodA
methodA does a little more work and then returns
One way to do the little more work was to call methods on an object passed into methodA as parameter. That should work, as self does not play a role there.
Another way to do that work was to call a method of VC1 using self which obviously causes a crash. So as long as one does not use self, everything should be fine.

Yes, you should fix it, but based on what you are saying your app architecture must be to a greater or lesser extent wrong. You are trying to implement an algorithm distributed across view controllers that really needs an object that lives across the lifetime of the objects you are dealing with. Such needs a mediator object.
Actually I suspect you may not need to be implementing that algorithm at all and another approach that works better with how controllers are instantiated and how control gets passed around the app would work fine, but you haven't posted sufficient info for me to be able to advise on that.
However having said that, implementing an overarching controller could certainly be used to solve your problem. A good way to do this is often to subclass your current root view controller (or better still a subclass that implements a category you define). So for example, if it is a UINavigationController you are using, create UINavigationController subclass, change the class of it's representation in your Storyboard (assuming you are using storyboards) and do the work of coordinating display and dismissal of other view controllers in there.
Also check out the Mediator design pattern http://cocoapatterns.com/ios-view-controller-transitions-mediator-pattern/
As a note, generally these days you can avoid having any object properties for strongly holding view controllers. Usually the root view controller holds strong references to any view controller it needs to present, lazy invocation should be used to present view controllers that are not currently presented or stored in an existing navigation controller stack (which keeps the memory utilisation profile in good shape) and any other child view controllers can be added in to your view controller heirarchy using the addChildViewController: method in which case they are strongly held in the childViewControllers array property.
You may want a convenient name for a view controller, but actually I would recommend writing a small bit of code for as the implementation of any such property that will identify the controller you need from amongst those in the Apple supplied properties, and dynamically retrieve it. This may seem like hard work, but it's worth it and actually, paradoxically, decreases code complexity and helps ensure you stay working with the view controllers the way Apple intended. Doing anything else increases pain.
Using separate object properties for holding references to view controllers will usually only duplicate mechanisms the existing Apple classes already provide you with. Such unnecessary duplication increases code complexity and can introduce bugs and memory management issues (of the kind you are in fact describing).
Sorry this answer is quite general, but you are seeking an answer to the wrong question. From what you have said it's clear that at some level you need to address your app architecture.

I agree the architecture seems flawed but as you say it is inherited code and not trivially small maybe some compromises must be made.
I am thinking since self (or any instance variables or properties) cannot be called anyway perhaps you could make the methods you need to call class methods (+) rather than instance methods (-). Class methods are obviously safe to call without an object instance.

Related

Documentation on not calling viewDidLoad directly?

The [UIViewController viewDidLoad] method is called by the system after loading the associated view (obviously?). A common belief -- which I share -- is that viewDidLoad should not be called directly †. However, I can't find this guidance in the documentation, nor anything else from Apple. Does it exist?
For comparison, the loadView documentation says
You should never call this method directly.
† Excepting [super viewDidLoad] in an overridden method.
I don't think there's any rule that forbids it. I don't mean "there's a rule we all know, it's just not written down." I mean "I don't think there's any rule that forbids it." You are, as best I am aware, free to call viewDidLoad whenever appropriate (including its super).
That doesn't mean you should call it. But then you almost certainly should never call OSCompareAndSwap either. In both cases, if you had a good reason and knew what you were doing, it could be appropriate to call. But it's unlikely to come up.
While I can't think of a time I've had to call viewDidLoad directly, I have had to manually call viewWillAppear and viewDidDisappear to manage view lifecycle in a custom container view controller. There's nothing that forbids calling view lifecycle methods if that's what you mean.
That said, it would be bad practice to call a view lifecycle method if you didn't mean "the view has transitioned into this state." And since it's pretty hard to get into a situation where you have loaded the view, but viewDidLoad won't be called, it's hard to imagine many cases where it would be useful. And you shouldn't call a method uselessly. So that's the only rule at play here as far as I'm aware.
It is not mentioned explicitly but if you would call it, you would somehow violate the "contract" of the method specified in its documentation:
Called after the controller's view is loaded into memory.

Massive Parent-Child and delegate pattern

I'm facing with a complex design problem. Due to a hard designed graphic I can't use Apple navigation pattern as UINavigationController or other ones.
This is the app diagram
Black arrow: protocols direction
Blue arrow: parent-child pattern direction
I created this flow because I want to maintain the code inside the single ViewController clear and isolated: I thought about them as modules that they can be used somewhere in other apps.
The RootViewController is the MainVCs position manager. It decides which is the current view-controller that it must be showed and it configures it based on its status (modified by delegate methods).
The single MainVC doesn't know that RootVC exists and it call Root using protocols. The single ChildViewController doesn't know that its MainVC exists and it call the Main using protocols and so on.
Code is clear and much easy to understand, my purpose, but when I have to apply a modify to the skeleton (RootVC) from the ChildViewControllerN, child of the umpteenth ChildViewController, child of the umpteenth MainViewController, I have to propagate the protocol until the RootViewController.
My first question is: is this pattern correct? What do you think about it?
My second question is: is there a limit point where I haven't to use delegate pattern but something like KVO?
ADDING
I read a university lecture about the composite pattern that it says:
A composite object knows its contained components, that is, its children. Should components maintain a reference to their parent component?
Depends on application, but having these references supports the Chain of Responsibility pattern
So, according to the Chain, I can maintain a reference of the parent but I have to declare a custom interface for this kind of reference. However, doing this I will decrease the number of protocols, but the second question still be unanswered
Opinion:
When I go beyond a single level of parent/child relationships, I tend to stop using delegates and move to NSNotification. Frequently, I go directly to NSNotification to reduce dependencies. I prefer that to KVO because it is explicit, whereas KVO is harder to debug as the project progresses.
(Example: what looks like a simple variable assignment on a background thread results in a hard-to-diagnose crash if a listener is deallocated on the main thread between the moment of assignment and the KVO delivery.)

Questions about VIPER - Clean Architecture

I've been reading about Clean Architecture from Robert Martin and more specifically about VIPER.
Then I ran into this article/post Brigade’s Experience Using an MVC Alternative which describes pretty much what I'm currently doing.
After actually trying to implement VIPER on a new iOS project, I've ran into some questions:
Is it ok for the presenter to query information in the view or should the "information passing" always start from the view?
For example, if the view triggered some action in the presenter, but then, depending on the parameters passed through that action, the presenter might need more information.
What I mean is: the user tapped “doneWithState:”, if state == “something”, get information from the view to create an entity, if state == “something else”, animate something in the view. How should I handle this kind of scenario?
Lets say a "module" (group of VIPER components) decide to present another module modally. Who should be responsible for deciding if the second module will be presented modally, the first module's wireframe or the second module's wireframe?
Also, lets say the second module's view is pushed into a navigation controller, how should the "back" action be handled? Should I manually set a "back" button with an action in the second module's view controller, that calls the presenter, that calls the second module's wireframe that dismiss and tells the first module's wireframe that it was dismissed so that the first module's view controller might want to display something?
Should the different modules talk only through the wireframe or also via delegates between presenters? For example if the app navigated to a different module, but after that the user pressed "cancel" or "save" and that choice needs to go back and change something in the first module (maybe display an animation that it was saved or remove something).
Lets say a pin was selected on a map, than the PinEditViewController is displayed. When going back, the selected pin's color might need to change depending on use actions on the PinEditViewController. Who should keep the state of the current selected pin, the MapViewController, the MapPresenter or the MapWireframe in order for me to know, when going back, which pin should change color?
1. May the Presenter query information from the view
To answer this to your satisfaction, we need more details about the particular case. Why can't the view provide more context information directly upon callback?
I suggest you pass the Presenter a Command object so the Presenter doesn't have to know what to do in which case. The Presenter can execute the object's method, passing in some information on its own if needed, without knowing anything about the view's state (and thus introducing high coupling to it).
View is in a state you call x (opposed to y and z). It knows about its state anyway.
User finishes the action. View informs its delegate (Presenter) about being finished. Because it is so involved, it constructs a Data Transfer Object to hold all usual information. One of this DTO's attributes is a id<FollowUpCommand> followUpCommand. View creates a XFollowUpCommand (opposed to YFollowUpCommand and ZFollowUpCommand) and sets its parameters accordingly, then putting it into the DTO.
Presenter receives the method call. It does something with the data no matter what concrete FollowUpCommand is there. Then it executes the protocol's only method, followUpCommand.followUp. The concrete implementation will know what to do.
If you have to do a switch-case/if-else on some property, most of the time it'd help to model the options as objects inheriting from a common protocol and pass the objects instead of the state.
2. Modal Module
Should the presenting module or the presented module decide if it's modal? -- The presented module (the second one) should decide as long as it's designed to be used modally only. Put knowledge about a thing in the thing itself. If its presentation mode depends on the context, well, then the module itself can't decide.
The second module's wireframe will receive message like this:
[secondWireframe presentYourStuffIn:self.viewController]
The parameter is the object for which presentation should take place. You may pass along a asModal parameter, too, if the module is designed to be used in both ways. If there's only one way to do it, put this information into the affected module (the one presented) itself.
It will then do something like:
- (void)presentYourStuffIn:(UIViewController)viewController {
// set up module2ViewController
[self.presenter configureUserInterfaceForPresentation:module2ViewController];
// Assuming the modal transition is set up in your Storyboard
[viewController presentViewController:module2ViewController animated:YES completion:nil];
self.presentingViewController = viewController;
}
If you use Storyboard Segues, you'll have to do things a bit differently.
3. Navigation hierarchy
Also, lets say the second module's view is pushed into a navigation controller, how should the "back" action be handled?
If you go "all VIPER", yes, you have to get from the view to its wireframe and route to another wireframe.
To pass data back from the presented module ("Second") to the presenting module ("First"), add SecondDelegate and implement it in FirstPresenter. Before the presented module pops, it sends a message to SecondDelegate to notify about the outcome.
"Don't fight the framework", though. Maybe you can leverage some of the navigation controller niceties by sacrificing VIPER pure-ness. Segues are a step into the direction of a routing mechanism already. Look at VTDAddWireframe for UIViewControllerTransitioningDelegate methods in a wireframe which introduce custom animations. Maybe this is of help:
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return [[VTDAddDismissalTransition alloc] init];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
return [[VTDAddPresentationTransition alloc] init];
}
I first thought that you'd need to keep a stack of wireframes similar to the navigation stack, and that all "active" module's wireframes are linked to one another. But this isn't the case. The wireframes manage the module's contents, but the navigation stack is the only stack in place representing which view controller is visible.
4. Message flows
Should the different modules talk only through the wireframe or also via delegates between presenters?
If you directly send another module B's object a message from Presenter A, what should happen then?
Since the receiver's view is not visible, an animation cannot start, for example. The Presenter still has to wait for the Wireframe/Router. So it has to enqueue the animation until it becomes active again. This makes the Presenter more stateful, which makes it harder to work with.
Architecture-wise, think about the role the modules play. In Ports/Adapters architecture, from which Clean Architecture burrows some concepts, the problem is more evident. As an analogy: a computer has many ports. The USB port cannot communicate with the LAN port. Every flow of information has to be routed through the core.
What's at the core of your app?
Do you have a Domain Model? Do you have a set of services which are queried from various modules? VIPER modules center around the view. The stuff modules share, like data access mechanisms, don't belong to a particular module. That's what you may call the core. There, you should perform data changes. If another module becomes visible, it pulls in the changed data.
For mere animation purposes, though, let the router know what to do and issue a command to the Presenter depending on the module change.
In VIPER Todo sample code:
The "List" is the root view.
An "Add" view is presented on top of the list view.
ListPresenter implements AddModuleDelegate. If the "Add" module is finished, ListPresenter will know, not its wireframe because the view is already in the navigation stack.
5. Keeping state
Who should keep the state of the current selected pin, the MapViewController, the MapPresenter or the MapWireframe in order for me to know, when going back, which pin should change color?
None. Avoid statefulness in your view module services to reduce cost of maintaining your code. Instead, try to figure out whether you could pass a representation of the pin changes around during changes.
Try to reach for the Entities to obtain state (through Presenter and Interactor and whatnot).
This doesn't mean that you create a Pin object in your view layer, pass it from view controller to view controller, change its properties, and then send it back to reflect changes. Would a NSDictionary with serialized changes do? You can put the new color in there and send it from the PinEditViewController back to its Presenter which issues a change in the MapViewController.
Now I cheated: MapViewController needs to have state. It needs to know all pins. Then I suggested you pass a change dictionary around so MapViewController knows what to do.
But how do you identify the affected pin?
Every pin might have its own ID. Maybe this ID is just its location on the map. Maybe it's its index in a pin array. You need some kind of identifier in any case. Or you create an identifiable wrapper object which holds on to a pin itself for the duration of the operation. (That sounds too ridiculous for the purpose of changing the color, though.)
Sending Events to Change State
VIPER is very Service-based. There are lots of mostly stateless objects tied together to pass messages along and transform data. In the post by Brigade Engineering, a data-centric approach is shown, too.
Entities are in a rather thin layer. On the opposite of the spectrum I have in mind lies a Domain Model. This pattern isn't necessary for every app. Modeling the core of your app in a similar fashion may be beneficial to answer some of your questions, though.
As opposed to Entities as data containers into which everyone might reach through "data managers", a Domain protects its Entities. A Domain will inform about changes proactively, too. (Through NSNotificationCenter, for starters. Less so through command-like direct message calls.)
Now this might be suitable for your Pin case, too:
PinEditViewController changes the pin color. This is a change in a UI component.
The UI component change corresponds to a change in your underlying model. You perform the changes through the VIPER module stack. (Do you persist the colors? If not, the Pin Entity is always short-lived, but it's still an Entity because its identity matters, not just its values.)
The corresponding Pin has changed color and publishes a notification through NSNotificationCenter.
By happenstance (that is, Pin doesn't know), some Interactor subscribes to these notifications and changes its view's appearance.
Although this might work for your case, too, I think tying the edit
This answer may be a bit unrelated, but I'm putting it here for reference. The site Clean Swift is an excellent implementation of Uncle Bob's "Clean Architecture" in swift. The owner calls it VIP (it still contains the "Entities" and the Router/wireframe though).
The site gives you XCode templates. So let's say you want to create a new scene (he calls a VIPER modules, "scenes"), All you do is File->new->sceneTemplate.
This template creates a batch of 7 files containing all the headache of the boilerplate code for your project. It also configures them so that they work out of the box. The site gives a pretty thorough explanation of how every thing fits together.
With all the boiler plate code out of the way, finding solutions the questions you asked above is a bit easier. Also, the templates allow for consistency across the board.
EDIT -> In regards to the comments below, here's an explanation as to why I support this approach -> http://stringerstheory.net/the-clean-er-architecture-for-ios-apps/
Also this one -> The Good, the bad, and the Ugly about VIPER in iOS
Most of your questions are answered on this post: https://www.ckl.io/blog/best-practices-viper-architecture (sample project included). I suggest you pay special attention to the tips for Modules initialization/presentation: it's up to the source Router to do it.
Regarding back buttons, you can use delegates to trigger this message to the desired module. This is how I do it and it works great (even after you insert push notifications).
And yes, modules can definitely talk to each other by using delegates as well. It's a must for more complex projects.

Singleton-Like UIView Access?

I have a UIView I need to access the properties of from all around my app. I know you can't create a Singleton around a UIView object, so what might be a good way of doing similar?
E.g. The view has a label. From any view controller in my app I want to be able to change the text of this view (sitting in a parent view controller).
Thanks.
EDIT:
Success! Using KVO to track changes in my Singleton object worked a charm, and a very simple solution.
I think what you’re trying to do violates the separation of concerns of the MVC pattern: The only thing that should interact with a view is its controller. In your case, you should probably be creating a model that is watched by your view controller (maybe through key–value observing), and then the controller can propagate the necessary changes to your view.
If you know (read: you really know for now and forever!) that there will be at most one instance of that view alive at one point in time, you can just use a global variable to store that. Or use a class property on that view - which is as close as being a singleton as possible.
Or you might just fix your design, which has proven to be the better choice in every case I can remember. :) Just add some forward and backward references in your classes (and stick to MVC principle). It takes much less time to implement that worrying about those awkward workaround, and it will pay of rather sooner than later.

UIViewController's initWithNibName: a reason behind this design?

I tend to agree with Joe Conway’s and Aaron Hillegass’s analysis, as reported today by Ole Begemann in http://oleb.net/blog/2012/01/initWithNibName-bundle-breaks-encapsulation/
Basically, they state that the NIB's filename is an implementation detail of the corresponding UIViewController class, and that it is not the business of the calling class to pass in the NIB's filename in the init method.
I was wondering if there was any particular reason for this design choice from the creators of AppKit/UIKit, or if it is merely a mistake — and, in the latter case, why it wasn't corrected when UIKit came out, which would have been a good opportunity.
If any Objective-C old-timer could provide the historical background to this, that would be nice to get a better understanding of the framework we use every day.
I suspect it was done this way so that a UIViewController could have basic functionality as a controller without requiring any subclassing. For example, if you're just pushing a "Credits" view on a navigation controller, and the view has nothing but static text, you could get away with not creating a UIViewController subclass. You could simply create a UIViewController directly and pass it the nib that contains your static text.
Most of the time, of course, you're going to want some level of interaction with the presented content, in which case a custom controller is necessary. But in theory, it's not always required.
It has come to my mind today that maybe Storyboards are precisely a response to that issue. Because Storyboards are defined at application-level, there is no more violation of encapsulation, merely a change of level. UIViewController subclasses become the detail implementation of the Storyboard as a whole.
It still doesn't explain the historical reasons behind the original design, but at least they have done something to address the issue — and, as often with Apple, in a very elegant way.

Resources