Currently I am working on building an iOS app that asynchronously connects to a web server. I make about 5 different calls to the web service, depending on which view controller I am in. On a lot of the views, I end up making the same calls, so I have a lot of identical/similar code. Do you guys have any suggestions on how I can limit the amount of code reuse I am making. I was thinking about creating a special class that has the method/code for all these asynchronous calls, then on each View controller, I can just instantiate the special class and invoke whatever methods I want. The problem with this is that since I am making asynchronous calls, how will I know which view controller to send the data back to (via a callback). I know there should be a simple, elegant way to achieve this but I am just new to this way of thinking so help would be greatly appreciated.
1 Answers
Usually what I do is a class that is responsible for the requests (or part of them depending on the amount of requests you have and how they are logically related).
Imagine that you have a NetworkManager. In this manager you can have a singleton if you need to persist state or just use class methods. All methods should have at least a completion block that will be called when the async method that you use for your server has the response.
The block can be defined with a typedef:
typedef void (^NetworkCompletionBlock)(NSError *error, NSArray* data);
Then you call methods like this:
+(void) requestInfoFromServerOnCompletion:(NetworkCompletionBlock)onComplete;
Then, on your method, you call your async functions and when they are complete you call the onComplete block with the parameters he requests, like this:
if(onComplete)
onComplete(yourError, yourDataArray);
To call this class method just do:
[NetworkManagerrequestInfoFromServerOnCompletion:^(NSError *error, NSArray* data)){
if(error)
NSLog(@"Ops, an error ocurred");
else
NSLog(@"Received data: %@", data);
}];
You can also have two blocks, one for error and one for completion.
Depending on how you are doing your requests you might need to save the block in the NetworkManager. Imagine that you use a NSURLConnection with delegates. You had to save your block in a networkManager singleton and then call it when the request is complete.
To do this you need to declare a property on your singleton:
@property (nonatomic, copy) NetworkCompletionBlock onRequestCompletedBlock;
And then on your method you do:
self.onRequestCompletedBlock = onComplete;
When the request is completed you can call with:
self.onRequestCompletedBlock(requestError, requestDataArray);
Note that if you do this you need to be careful with retain cycles.

- 1
- 1

- 14,081
- 3
- 67
- 82
-
I am a little confused here, specifically on the part where you say "Then, on your method, you call your async functions and when they are complete you call the onComplete block with the parameters he requests." The onComplete block part is kinda confusing me. – AyBayBay Jan 21 '14 at 20:51
-
So your passing in a Code Block as a parameter? – AyBayBay Jan 21 '14 at 20:56
-
Yes, you pass a call block as an argument. It would be far more easy if you could say how you are doing your calls to your servers. I will try to be more concrete in a sec. – Tiago Almeida Jan 21 '14 at 21:12
-
I think the suggestion of passing in a code block as an argument was enough to help solve my problem. I was not aware you could do that but it makes sense that you can and it makes my design easier to achieve now. Thanks for the suggestion – AyBayBay Jan 21 '14 at 21:47
-
I found that I don't even have to pass in a code block, I can just send over an NSObject* instance, and invoke it (essentially pass in a reference to the calling view controller, when calling my class that handles requests) – AyBayBay Jan 21 '14 at 22:45
-
@AyBayBay you can do that but I wouldn't suggest you to do it. You should separate the two concepts. The way you are doing isn't flexible. Imagine that you need to update your interface one day when the server has an answer (positive or negative) how would you do it? Having that block gives you a clear spot for you to introduce changes when you receive an answer from the server. Don't be lazy on this one. Isn't that hard and it will be a life saver on the long run :) – Tiago Almeida Jan 21 '14 at 22:49
-
So my current design is I have one class that basically has all the asynch method calls. When a view controller makes an async method call, it instantiates this class and calls the respective method, for example user login. When calling the method, the method accepts as a parameter a generic (NSObject *)sender, so when making the call, the View Controller class also passes in self (this is the reference I was kind of talking about). Now from within the method and asynch code block, I call [sender callbackmethod]. – AyBayBay Jan 21 '14 at 23:32
-
How does it now which callback method? Well all View Controllers are required to implement the same callback method for each synch call, For example if the async call method is "processLoginInfo", the respective CallBack function on the View Controller is "RecievedLoginInfo", so I could just invoke [sender RecievedLoginInfo] through means of selectors – AyBayBay Jan 21 '14 at 23:33
-
There is some repetition of code in this design but it is MUCH less than repeatedly calling the same asynch functions/similar ones for each respective View Controller. The only repetition of code here is just the callback handler functions, now each View Controller just needs to have those and each cb function is like two lines of code, just setting some self.properties. Let me know what you think of this design – AyBayBay Jan 21 '14 at 23:36
-
Please post a gist with the example you have. Is hard to follow in comments. But as far as I could tell you passing self to that class? Don't do that please. Separate your concepts. What if the view controller changes the interface? This can also lead to retain cycles that are hard to track. Don't avoid blocks because you are unfamiliar with them. If you want you can also create a delegate instead of the block, but it is important that you Network class has 0 dependencies with view controllers. – Tiago Almeida Jan 21 '14 at 23:39
-
I also think its pretty extensible. You have one class for asynch method handling, any new View Controller that comes about requiring to process web server data, just use the central class and make sure your callback functions have the documented method signatures so you do not have to go in and mess with the class that handles asynch calls implementation – AyBayBay Jan 21 '14 at 23:41
-
Here is a gist that I just made, I hope it helps. I really appreciate you trying to help out. I separated the classes into the View Controller, and the class that makes my async calls for me. I think the code should be easy to follow along https://gist.github.com/curama/8550859 – AyBayBay Jan 21 '14 at 23:48
-
let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45757/discussion-between-tiago-almeida-and-aybaybay) – Tiago Almeida Jan 21 '14 at 23:56