How to "talk" back from object B to A? - ios

i have a view controller object A, that asks another object B for internet data. Object B implements: connectionDidFinishLoading:connection:
When object B is ready and has its data, the method above is called. But i want to update the UI of object A. Whats the best way to do this? I think i must use a protocol?

There are different ways to handle this. Setting up object A to be the delegate of object B would be a perfectly valid way. you'd then define a protocol that object B would use to communicate back to Object A.
Another way to pass a completion block from object A to object B in the call that asks for the data. Then in object B's connectionDidFinishLoading:connection: method, it would check if the completion block is nil and if it's not nil, call the block.
I have been using the block-based approach more and more lately. There is less setup, and the completion code is right in the method in Object A that invokes Object B, so it's easier to follow what's going on.
You might want to set up a block that takes a success/failure parameter, as well as an NSError object. That way if the connection fails, you can handle it gracefully, and even report the error to the user if you decide to.

Related

In ARC how does a child object tells parent object I am done, please release me (to avoid memory leaks)

My parent object creates a child object to do some async action. It involves some user interaction and that's one of the reasons I didn't use NSOperation. Only the child object knows when it has finished its task, then how does it tell its parent object that I am done, please release me to avoid memory leaks?
Currently, I come up with this, the parent object has a callback method called releaseChild, which is just child = nil; When the child object finishes its task it calls parent's releaseChild just to set itself to nil. Actually, I wrap the call in a dispatch_after but the idea is the same, the child object calls its parent to set itself to nil.
I was wondering is there a better way ?
----- update -----
I know the "normal" way to write my child is to create a UIViewController object, push it to UINavigationController. When it is finished user can pop it up, ARC will then release it. In that way, I don't need to worry about memory leaks (normally). But I think the question to release a child object when it is done and only it knows when it is done has a border application than writing a UIViewController object.
In the question:
Only the child object knows when it has finished its task, then how does it tell its parent object that I am done, please release me to avoid memory leaks?
and in a later comment:
the problem is the child object can't set itself to nil.
What it appears you need is a child object which controls its own lifetime. This is easily done; an object remains alive as long as there is a reference to it stored in a variable attributed as asserting strong ownership over references stored in it - and that attribute is the default for variable declarations. That variable can be global, local, instance, it doesn't matter... So to control your its own destiny an object just needs to keep a reference to itself.
The following code, copied from Manual object lifetime with ARC (a previous answer I wrote a few years ago, I can crib from myself ;-)), shows one way to do this:
#implementation MasterOfMyOwnDestiny
{
MasterOfMyOwnDestiny *alsoMe;
}
- (void) lifeIsGood
{
alsoMe = self;
}
- (void) woeIsMe
{
alsoMe = nil;
}
...
#end
In your case you can have the child set alsoMe during its initialisation, so the child starts off controlling its own lifetime. When the child decides it has finished its work it simply calls [self woeIsMe] as its final action.
Note: You can of course remove the methods and just set the instance variable directly within the child, making it hard for any other object to kill the child off.
If the parent needs to have a reference to the child for any reason, other than to keep the child alive, then it can store that reference in a variable attributed as asserting weak ownership of references stored in it, e.g. something like:
__weak MasterOfMyOwnDestiny *myChild = [MasterOfMyOwnDestiny new];
such a reference will not keep the object referenced by myChild alive, and will be automatically set to nil when that object dies.
Couple of possible solutions
1) Use protocol-delegation method to let child tell parent that its done (i am assuming thats what you are doing)
2) you can pass variable into the child and which gets set by child once its finishes execution and parent can periodically check its value and clear the child (not a big fan, but kind of polling method), Can be done with created background task or can be added to low priority queue.
3) Use NSNotificationCenter to send notification to parent and tell him works done. You can add userinfo to identify children among each other.
4) If you don't need to do anything specific after work is done just use dispatch_async and don't hold the reference, it will do its task and die down eventually
I would require more details to give you recommendation about any specific approach. If possible paste your code :)
If a child object performs an asynchronous operation, it would be most likely that it has a callback block that it calls when the operation is finished, either with success or with failure. And most likely the parent object has created the child, stored a reference, told the child to start the asynchronous operation, and given it the callback block. So that callback would be the perfect place to set some reference to nil.

Conceptional: two controller using the same calculation method - delegate?

I have two or even more view controllers (A and B) which uses the same calculation method. I would guess the best way is to put the calculation method in its own class (lets call it C), define a protocol and thats it. If this is right, how do I know how to address the delegate?
If I alloc/init an object of the class C (the one with the calculatormethod) e.g. in class B I have the object pointer in class B - thats ok. But how do I get the object pointer known in class A or even other classes (i.e. how do I tell those controllers which want to use the delegate (i.e the same calculation method), how to address the delegate once it is alloc/init by class B?
Any help is very much appreciated!
I have two or even more view controllers (A and B) which uses the same calculation method.
Unless this is for calculating view layouts, it probably indicates you've have an MVC violation. View Controllers typically should not calculate anything. Their job is to manage user interaction. Data and calculations belong in the model.
If it is a proper view controller calculation (like managing layout), then you're correct that you want a delegate. "Delegation" is what Cocoa tends to call the Strategy pattern. You move your algorithm into another object and that lets you vary the algorithm without varying the rest of the code.
So in one case you need access to some model object, and in the other you need access to some delegate. In either case, the solutions can be similar. I'll call either situation "C" as you have.
One solution, particularly is you're using a storyboard, is to create "C" in the storyboard and wire it with an IBOutlet. You can create any object you like in a storyboard. Just drag out an "Object" and set its class to the appropriate class. Wire it up just like anything else. (This is a technique that is commonly used for multi-view nib files on OS X, and I had remembered translating over to Storyboards, but it doesn't work for sharing objects across scenes, only within scenes; so it's not as useful on iOS.)
Another solution, particularly for the model, is to implement it as a singleton, or to have a separate singleton (a "model controller") that returns it. You should not use the app delegate for this; use a singleton made expressly for this purpose.
You can create "C" in the application delegate and pass it into the root view controller (this is a proper use of the app delegate, because it's part of global program initialization). The view controllers can pass the object as part of their segues. This is my preferred solutions for passing model objects around.
If it really is a layout calculation delegate, this is probably part of some kind of configuration system (assuming it can change). The current configuration can be treated as a piece of the model, and all the above techniques still work.
If it really is just shared algorithms and doesn't vary, don't forget C functions. There is no rule that you must put all code into methods. Functions are ideal for stateless calculation. Categories can be used this way to, but simple functions have fewer complexities.
What you are saying is that both classes A and B have a common dependency (could be class C or simply a protocol C).
A and B don't need to know anything about how they are instantiated, they just need to know that they will be eventually provided with an instance implementing (protocol) C.
Another important thing is that you probably don't want C to be hold with a strong reference by either A or B.
I would look at which class F could have the responsibility to instantiate A and B.
The responsibility of this class (which could be described as a Factory) could also be to provide instances of A and B with a C instance.
So what I would do: Define a "factory" class that has methods to build instances of A and B.
Each of these methods would also provide with a C instance. This C instance could be a property of the factory class if you want it to be shared (or this factory class could also pick the C instances from a pool of available C instances).
UPDATE: not practical if you are using storyboards to instantiate your controllers. In this case you probably want to go with other given answer or implement your shared computational functions as methods of a singleton class C (see How to pass object between several views in storyboard, iOS Dev for example)
Use a superclass for A and B (and any number of additional controllers) that contains the calculation method. By using a superclass, you don't have to alloc init another class or use delegates, all the subclasses will have access to the method.
Another approach that would be more general would be to implement a category on UIViewController to add the calculation method. This way, any controller that descends from UIViewController (UITableViewController, UICollectionViewController, etc.) would have access to that method.
After Edit:
I see in your comments that your calculations have nothing to do with the controllers, just some sort of algorithm, so a category or subclass of UIViewController is probably not the best way to go. If you want to do it in another class, any controller that needs to use it, can instantiate an instance of that class, set itself as delegate, and get the result back through the delegate method (that is, if you even need a delegate -- if the calculation is fast, then you can just return a result from the method rather than using a delegate). After your controller gets the result back, the instance should be deallocated. You don't have to worry about which controller set the delegate, since each controller creates its own instance of the calculation class, and sets itself as delegate. I use this kind of structure for apps that need to do downloads from a server from multiple controllers. The download class is instantiated, does its work, sends back the result in a delegate method, and then gets deallocated. It only sticks around for as long as it needs to to do its work.

what happens if delegate doesnot exist anymore?

I came around a interesting issue while working on my app. Imagine the scenerio where
There exist one object, Lets call it A.
A, then creates an object(B) of some delegation based class, say NSURLConnection.
A assigned itself as delegate of B, provided A has implemented all the required delegate methods.
A asks B to start its processing. In our example i.e. fetching data from some server.
As soon as B finished fetching data, it will call some specified method of A.
In the last step, suppose while calling the methods of A, B finds that the A object doesnt exist anymore. Then what happens???
I'm not sure but does it cause crash?
If yes, then please suggest me how to avoid the situation.
In my case I assigned the viewcontroller as delegate of some object, say X in viewDidLoad method. There are cases when viewcontroller get destroyed before X calls the delegate methods defined in the viewcontroller.
If assigning X's delegate to nil solves the problem. Then where
should i do that.
In short, which method is called only once while unloading phase of view controller likewise
viewDidLoad in its loading phase.
The best way to achieve this kind of communication between classes (where class A could be deallocated at any time) is listening to NSNotifications.
As you stated , using weak(assign) delegates is dangerous and requires extra thought.
Using strong delegates could as well create a memory bloat (why should we retain a view controller so long after popping it from the view anyway?).
For more on NSNotificationCenter and notifications , you can find a lot of info in the SDK docs.. for specific questions, you know where to ask..
You should not reach a situation where one object holds a reference to another object which may be deallocated somewhere else without the owner object being notified.
Either when deallocating object A notify object B (by making member a nill in object B for example) or modify your design/flow to never allow A to be deallocated before B finishes (e.g. retain A when assigning as a delegate in B if possible)
Checking against a valid delegate object should be sufficient enough.
if (delegate)
[delegate method];

Multiple Delegates in iOS

I am making an object that goes to download stuff for all of my view controllers. The object is singleton instance and has a callback method with received data once the download is completed. It also has a delegate property so that it knows which object to call back to after the download is done.
There are multiple controllers that use this shared instance, and my question is how to call back to the correct view controller that requested the download.
My approach is to use delegation, but the problem is that since other view controllers are also its delegate, the download object could call back to every object and this will be hard to track.
I've worked on projects where people have attempted to use multiple delegates and it's basically a bad idea. The delegate pattern is about a 1 to 1 relationship between a class and it's delegate. Whilst it is possible to achieve some level of multiple delegation through switching the delegates in and out, it's more likely to lead to unpredictable behaviour and bugs.
My recommendation would be to change how you are thinking about this. You have two options as I see it:
Switch to an Observer pattern where you can register multiple observers which your main class can interact with. This is useful where your observers all implement the same protocol and where your main class wants to be aware of the observers and interaction with them.
Broadcast NSNotifications to indicate state changes and events. Here is a more decoupled approach because the main class does not need to know who is listening and does not directly interact with them. Other can start and stop being notified at their leisure. It also has the advantage that you do not need to create or implement a separate protocol. Instead you register the classes that need to know about changes with the NSNotificationCenter which in turns handles all the routing of notifications for you.
It actually sounds like the delegate pattern might not be the best approach here.
I would look into NSNotificationCenter instead.
The basic idea is that your singleton doing the net connection posts a notification (with something like postNotificationName:object:userInfo:) , saying that new data is available. Within this notification, you can pass a dictionary object (userInfo) that holds the data you've fetched, or info on what parts of your Model contain updated data.
Then, your other view controllers can register themselves to 'observe' these notifications by calling addObserver:selector:name:object:. Generally speaking, when a vc becomes visible I call addObserver, and removeObserver when it's being hidden or transitioned out.
Good luck!
Delegation doesn't seem like the right solution to this problem. How about requiring the requesting view controller to provide an object (its self) and a selector for you to call as a completion notification? Of course, you'll need a place to store that object and selector until the download completes. Hopefully you have (or could create) an object for this.
i recommend to use one of these ways
observer:
when use data that you want to inform other object are near to primitive ones.for example when you are using 'NSMutableArray' you can not inform the change in one of object by the standard implemented pattern at least you need to implement one for your self that is not reusable that much
Notification
when your interaction with destination object (those need to be inform) is in one-way.it means you don't need any acknowledge or other data back from them.
delegate
when there is one object to inform at each time step.
note:block use for success and fail is not a pattern to broadcast data its about to queue task when you don't know when they are finishing or failing like network operations
EDIT:
how to create notification | multi delegate issues and implementation
While I agree with most of the answers here, if you did actually want to achieve multiple delegates you could potentially declare an array of delegates and send messages to all delegates within that array. If your protocol has optional delegate methods you safely check using responds(to aSelector: Selector!) -> Bool before invoking (being mindful of memory management, as those delegates would be strongly referenced in the array). Again I do agree that multiple delegates is likely a bad architectural idea and using blocks or notification center would suit your needs better.
One approach, which works for me if you only have one other object to forward messages to is to create a forwardingDelegate This does not end up with issues of hard to debug ordering of delegates and it does not unnecessarily create a dependency on the other object. Keep in mind, if you have many objects then this might not be the best approach, it is mainly for one additional object but this could be extended to support an array of objects so long as there is one that receives the SDK and forwards it to the other objects [1]. Note that every method that is needed for the forwarded object needs to pass it along, even if it is not used by the forwarding object.
For example, if I need to forward the messages coming from the mapView delegate:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// handle this object here.
if ([self.forwardingDelegate respondsToSelector:#selector(mapView:regionDidChangeAnimated:)])
{
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
}
// or handle this object here.
}
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
The forwarding property would be declared like this.
#property (nonatomic) id<MKMapViewDelegate> forwardingDelegate;
And the other object would adopt the protocol as if it were receiving the original message.
[1] The array approach for multiple delegates may get tricky because then you don't have as much control over what order the delegates get called, as was mentioned in other posts.

How to set the FBRequest delegate to nil in multiple different objects

I'm using the Facebook sdk for ios and I'm facing an issue on how to safely set the delegate to nil. My facebook object is a property of the appDelegate and I'm using this object in multiple different objects to retrieve different information. So, say that object A, B and C conform to the FBRequest protocol and are set as the delegate of the facebook object. Now in the dealloc method of object A I want to make sure that object A is no longer a delegate, so I could do: facebookObj.delegate = nil. However, I feel that this would affect the other delegate objects B and C. Am I thinking correctly? Is there any way to remove only the object A from the facebook delegates without affecting objects B and C?
Hope the question makes sense.
Thanks very much.
I think you have an separate FBRequest object for each request that you fire off from your A, B and C objects, no? From what i understand, the FBRequest object only lives while the request is processing. Once its complete or fails the object goes away, no? Now of course, if you keep a reference to this request it will look like its there because you have an address to it but if you try sending messages it will crash (Unless using ARC with weak references which i doubt you are using).
Try this from each of your objects (A, B & C):
NSLog(#"FBRequest address %#", your_fbrequest_object);
And see if it always prints the same address or different ones.

Resources