Can blocks be used as replacement for delegates? - ios

I want to write a custom delegate method to receive an event in one of my view controllers from another view controller. Should I use blocks here instead of delegates. Which is the preferred one ?
#protocol MyClassDelegate
-(void)doSomethingInDelegate;
#end
#interface MyClass : NSObject
#property id<MyClassDelegate> delegate;
-(void)doSomething
#end
#implementation MyClass
-(void)doSomething
{
[self.delegate doSomethingInDelegate];
}
#end
#interface MyOtherClass<MyClassDelegate> : NSObject
...
#end
#implementation MyOtherClass
-(void)doSomethingInDelegate
{
NSLog(#"Doing something in delegate");
}
#end

In most cases, if you have a very small number of delegate methods (ideally just 1), then blocks may be a good replacement. If you have several delegate methods, then blocks can become awkward.
UITableView has dozens of delegate methods between UITableViewDelegate and UITableViewDataSource. Configuring that with blocks would be unwieldy and make code reuse very difficult. If a particular way of "being the delegate" may be highly reusable (like in UITableViewController), then delegates are a much more powerful pattern.
On the other hand, if your delegate would wind up having just a single "thisActionFinished:` method, then a delegate is likely overkill and it's better to just pass a block. There are many cases that this is true, and we used to have to need to create a lot of one-method delegate protocols, and it was a bit of a pain. Blocks made that common pattern a lot easier.
But it's not a universal replacement for delegation, and blocks have many other purposes that have nothing to do with callbacks. So it's important to learn both techniques.
Looking to your specific example, there are several mistakes. Let's do it in both delegate and block forms.
Delegate
// Since the protocol needs to know about the class, you need to warn the
// compiler that this class exists.
#class MyClass;
// Declare the delegate protocol. Delegate method names should follow this
// pattern with "did", "should", or "will" in their names. Delegate methods
// should always pass the delegating object as the first parameter. A given
// delegate may be delegating for several instances.
#protocol MyClassDelegate
-(void)myClass:(MyClass *)class didSomething:(id)something;
#end
// Declare the class that has a delegate. Notice that `delegate` should be `weak`
// here. In your example, it's `strong`, and that will almost always lead to a
// retain loop. With rare exceptions, delegates are not retained.
#interface MyClass : NSObject
#property (nonatomic, readwrite, weak) id<MyClassDelegate> delegate;
-(void)doSomething;
#end
// Do the thing
#implementation MyClass
-(void)doSomething {
[self.delegate myClass:self didSomething:#"SOMETHING"];
}
#end
// The delegate object almost always has a strong pointer to the thing it delegates
// for. That's why you want the `delegate` property to be weak.
// Note that your syntax was wrong. "MyOtherClass <MyClassDelegate>". That's
// the new generic syntax, not the protocol syntax. Protocols go at the end.
#interface MyOtherClass : NSObject <MyClassDelegate>
#property (nonatomic, readwrite, strong) MyClass *c;
#end
// And the obvious impl
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
self.c.delegate = self;
}
return self;
}
-(void)myClass:(MyClass *)class didSomething:(id)something {
NSLog(#"Doing something in delegate");
}
#end
Block
Let's do the same thing if this were a block-based API.
// If your callback takes no arguments and returns nothing, then you can
// use dispatch_block_t here. But often you need parameters or return
// something, and for that you should usually make a typealias. Welcome to the
// spiral world of block syntax.
typedef void(^MyClassCallback)(id something);
// Instead of a delegate, we have a callback. We might have several. We might
// have a block that returns the row height. But if you're doing a lot of
// that, just use a delegate. Note that blocks should always be `copy`.
#interface MyClass : NSObject
#property (nonatomic, readwrite, copy) MyClassCallback callback;
-(void)doSomething;
#end
// And here's how you use the block. It's just like a function.
#implementation MyClass
-(void)doSomething {
if (self.callback != nil) {
self.callback(#"SOMETHING");
}
}
#end
// And the delegate.
#interface MyOtherClass : NSObject
#property (nonatomic, readwrite, strong) MyClass *c;
#end
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
// And here's the syntax for creating the block.
self.c.callback = ^(id something) {
NSLog(#"Doing something in delegate");
};
}
return self;
}
#end
Notice we don't need an extra method in the delegate just to hold one line of code, and we don't need to define a protocol. That's the big reason for the move to blocks for lightweight delegation. It keeps related code close together. But when the code gets complicated, "together" gets crazy, and blocks are not longer a good solution. Back to delegates, which do that very well.

Related

ios Objective C delegate methods

This is my first day of Objective C so I apologise for the lack of knowledge.
I need to import an existing SKD into an App and I done it successfully. Now I need to create the delegate methods and I don't understand how can I do it.
This is the structure of the header file included from the SDK (SDKManager.h):
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
#property (nonatomic, weak) id<SDKDelegate> delegate;
+(void)initialize:(NSString*)appId withKEY:(NSString*)key;
+(void)setHandler:(id)delegate;
#end
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items withResponse:(NSDictionary*)response;
#end
So, from my FirstViewController.m I was able to import the header and call two methods:
#import "FirstViewController.h"
#import "SDKManager.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[SDKManager setHandler:[UIApplication sharedApplication].delegate];
[SDKManager initialize:#"AppId"withKEY:#"1234"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
but I have noticed that I am not able to call the other methods (i.e. appDidReceiveTokens).
Actually the instructions require to create those methods but I have no idea where.
Any help is really appreciated.
Thank you
You do not call delegate methods directly in the files in which you are implementing the delegate methods. Review Apples documentation on the concept of Delegation.
To implement this properly you would adopt the delegate in your class, then implement the delegate methods that are #required and/or #optional.
You've correctly created the delegate protocol and a property to store the SDKManager's delegate.
Your setHandler: and initialize:withKEY: methods are class methods, whereas the delegate property belongs to each instance of SDKManager. Without seeing your implementation file (.m) for SDKManager, it's hard to know why you've set it up this way. You may be attempting to follow a singleton pattern - if so, read up on it, e.g. here.
The reason for that is you have class methods which sets the calls setHandler method and the delegate is property, so where do you assign the delegate and when and how do you call the delegate. I hope you understand what a class and instance is. So, you cannot call the delegate until you create instance of your object.
You have two different class methods which is used to set some attributes to the class, would it make sense to have them as property.
More generic and better way to do this would be like this,
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items
withResponse:(NSDictionary*)response;
#end
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate;
#end
#interface SDKManager ()
#property (nonatomic, copy, readonly) NSString *appId;
#property (nonatomic, copy, readonly) NSString *key;
#property (nonatomic, weak, readonly) id<SDKManagerDelegate> delegate;
#end
#implementation SDKManager
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate
{
if (self = [super init]) {
_appId = [appId copy];
_key = [key copy];
_delegate = delegate;
}
return self;
}
- (void)doSomeNetworkRequestHere
{
[self fetchTokenFromServer:^(NSDictionary *tokens, NSDictionary *response){
[self.delegate appDidReceiveTokens:tokens
withResponse:response];
}];
}
- (void)fetchTokenFromServer:(void(^)(NSDictionary *tokens, NSDictionary *response))completion
{
}
#end

Creating properties only visible to subclass in Objective-C

I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
#interface AbstractClass : UIView
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
…
#protocol ButtonDelegate
#required
- (void) buttonWasPressed;
#end
…
#interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
#implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Do like UIGestureRecognizer does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h.
Only import this in the *.m-files. Never include it in any public header.
All private properties and methods goes into *.m-files. Use the #interface ClassName ()
Example https://gist.github.com/hfossli/8041396
how to my subclass can inherit some properties from its superclass
without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
#interface Animal : NSObject
{
#protected
NSString *name; // default access. Only visible to subclasses.
}
#end
#implementation Animal
-(NSString*)description {
return name;
}
#end
#interface Cow : Animal
#end
#implementation Cow
-(id)init {
self=[super init];
if (self){
name = #"cow";
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
NSLog(#"%#", cow); // prints the name through internal access
// error accessing from the outside: NSLog(#"%#", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(#"%#", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those
properties
Which one is it?
Create an empty category on top of your implementation file (.m):
#interface AbstractClass()
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
#interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
#end
I am not sure about this, but give a try.
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's #synthesize, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
#interface Abstract ()
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
#implementation Abstract
#synthsize buttonDelegate;
#end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without #synthsize into all subclasses:
#interface MySubclass : Abstract
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of #synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.

ARC: Object - Delegate relationship

I am developing an ARC enabled project. From a view controller I am pushing MyClass,
- (void)pushMyClass {
MyClass *myClass = [[MyClass alloc] init];
[self.navigationController pushViewController:myClass animated:YES];
}
After doing some operations I am popping MyClass. The problem here is that MyClass is not getting deallocated. Following is how the classes look.
/* MyHelperClassDelegate */
#protocol MyHelperClassDelegate <NSObject>
- (void)helperDidFinishHelping:(MyHelperClass *)helper;
#end
/* MyHelperClass Interface */
#interface MyHelperClass : NSObject {
__weak id <MyHelperDelegate> delegate;
}
#property(nonatomic, weak) id<MyHelperDelegate> delegate;
- (void)startHelping;
#end
/* MyHelperClass Implementation */
#implementation MyHelperClass
#synthesize delegate;
- (void)dealloc {
delegate = nil;
}
/* MyClass */
#interface MyClass : UIViewController <MyHelperClassDelegate> {
MyHelperClass *helper;
}
#implementation MyClass {
- (void)dealloc {
helper.delegate = nil;
}
- (void)getHelp {
helper = [MyHelperClass new];
helper.delegate = self;
[helper startHelping];
}
- (void)helperDidFinishHelping:(MyHelperClass *)helper {
}
}
MyHelperClass calls a web service using NSMutalbleURLRequest & NSURLConnection to fetch some data and saves it to user defaults.
One thing to notice here is, if I comment the line helper.delegate = self;, then MyClass gets deallocated.
What to do to make MyClass get deallocated when it is popped out of navigation controller?
Thanks.
Your delegate code looks correct (except your use of an ivar, you don't show a #synthesize so you may have _delegate and delegate both). Its quite likely that something else is retaining MyClass. What I suggest you do is add a NSLog to your MyClass dealloc. Then push it, and immediately hit the back button and see if its dealloc'd or not. If not, then take a hard look at what you do in viewDidLoad et al and start commenting out sections of that code until you can get the dealloc.
Also, I assume you don't keep a strong reference in the class that pushes the MyClass object.
I agree with Chuck that one cannot say much from the code provided. But one reason why the MyClass object is not deallocated might be that it is retained by your helper object since delegate is declared as strong, and the MyClass object has the property helper also declared as strong. In this case you had a retain cycle, and none of them can be released.
The trick could possibly lie within the fact that you use NSURLConnection. It is not specified how you use this class with the code that you've provided, but please note the special considerations referenced in the NSURLConnection class reference:
Special Considerations: During the download the connection maintains a
strong reference to the delegate. It releases that strong reference
when the connection finishes loading, fails, or is canceled.

Singleton and Delegation

I read enough information about singleton and delegation. So, I think I understand what is singleton. About delegation I still confuse. I understand conception of delegation, but I need to create my protocol for understanding delegation.
Ok, I create singleton for work with my entities from CoreData. Maybe I wrong and it is not singleton, tell me please about it. My singleton is FetchData.
Fetchdata.h
#import <Foundation/Foundation.h>
#interface FetchData : NSObject <UIApplicationDelegate>
+(FetchData*) fetchData;
-(NSArray*)fetchLogin:(NSString*)name;
-(BOOL)newGroup:(NSString*)group forLogin:(NSString*)login;
-(NSMutableArray*)contactsForGroup:(NSString*)group;
-(BOOL)newContact:(NSString*)name surname:(NSString*)surname withDatas:(NSArray*)array;
//other methods
#end
Fetchdata.m
#import "FetchData.h"
#import "Contact.h"
#import "Login.h"
#import "Group.h"
#import "AppDelegate.h"
#interface FetchData ()
#property (nonatomic, strong) NSEntityDescription *loginEntity;
#property (nonatomic, strong) NSEntityDescription* groupEntity;
#property (nonatomic, strong) NSManagedObjectContext* context;
#property (nonatomic, strong) NSEntityDescription* contactEntity;
#property (nonatomic, strong) AppDelegate* appDelegate;
//other properties
#end
#implementation FetchData
#synthesize //my properties
+(FetchData*) fetchData
{
static FetchData* fetchData = nil;
if (!fetchData)
fetchData = [[super allocWithZone:nil]init];
return fetchData;
}
+(id)allocWithZone:(NSZone *)zone
{
return [self fetchData];
}
//implementation my methods
#end
So, it is very easy to work with CoreData now for me. I need only import FetchData and simply use methods for create/delete/change/add/sort...
SomeClass.m
#import "FetchData.h"
#define fetching [FetchData fetchData]
But I think that I can use for my aim delegation. Or maybe it is the best decesion as compared with singleton. So I want to remake singleton for delegation. And I need help with this question. What I must do?
If I understand correctly I need create protocol with all my methods from FetchData.h, FetchData.m I can leave without changes. And in SomeClass I need import FetchData and add my protocol. Like:
#import <Foundation/Foundation.h>
#protocol FetchingDelegate
//all methods from FetchData.h
#end
#interface FetchData : NSObject
#property (nonatomic, strong) id <FetchingDelegate> delegate;
#end
FetchData.m
#interface FetchData()
//all properties without changing
#end
#implementation FetchData
#synthesize //all properties and delegate
//implementation of methods
#end
SomeClass
#import "FetchData.h"
#interface SomeClass : NSObject <FetchingDelegate>
#end
#implementation SomeClass
-(void)viewDidLoad
{
FetchData* fetching = [FetchData new]
fetching.delegate = self
}
//and now I can use any methods from protocol like [fetching anyMethod]
//such I used with singleton
The idea of a singleton is that your entire app can access this one class. Multiple view controllers may need data coming from your database. In your case, I would change your fetchData method (and maybe change its name as it doesn't really follow convention now):
+(FetchData*) fetchData
{
static FetchData *fetchData;
dispatch_once_t token;
dispatch_once(&token, ^{
if (!fetchData)
fetchData = [super init];
}
return fetchData;
}
Delegates are meant for one-on-one communication, meaning that one object has a delegate and sends any messages to that one particular delegate.
That means that a singleton and delegation don't go well together. The singleton is made to send messages to multiple receivers, while the delegation pattern is meant for one-on-one communication. So you have two options: you could either not use a singleton and use the delegation pattern, or you could use a singleton, and use NSNotificationCenter to notify observers of changes.

Delegate declaration dilemma

I'm confused - I cannot understand what is the delegate is for?
The Application Delegate which is created by default is understandable, but in some cases I've seen something like this:
#interface MyClass : UIViewController <UIScrollViewDelegate> {
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;
BOOL pageControlUsed;
}
//...
#end
What is the <UIScrollViewDelegate> for?
How does it work and why is it used?
<UIScrollViewDelegate> is saying that the class conforms to the UIScrollViewDelegate protocol.
What this really means is that the class must implement all of the required methods defined within the UIScrollViewDelegate protocol. Simple as that.
You can conform your class to multiple protocols if you like:
#implementation MyClass : UIViewController <SomeProtocol, SomeOtherProtocol>
The purpose of conforming a class to a protocol is to a) declare the type as a conformant of the protocol, so you can now categorize this type under id <SomeProtocol>, which is better for delegate objects that objects of this class may belong to, and b) It tells the compiler to not warn you that the implemented methods are not declared in the header file, because your class conforms to the protocol.
Here's an example:
Printable.h
#protocol Printable
- (void) print:(Printer *) printer;
#end
Document.h
#import "Printable.h"
#interface Document : NSObject <Printable> {
//ivars omitted for brevity, there are sure to be many of these :)
}
#end
Document.m
#implementation Document
//probably tons of code here..
#pragma mark Printable methods
- (void) print: (Printer *) printer {
//do awesome print job stuff here...
}
#end
You could then have multiple objects that conform to the Printable protocol, which could then be used as an instance variable in, say, a PrintJob object:
#interface PrintJob : NSObject {
id <Printable> target;
Printer *printer;
}
#property (nonatomic, retain) id <Printable> target;
- (id) initWithPrinter:(Printer *) print;
- (void) start;
#end
#implementation PrintJob
#synthesize target;
- (id) initWithPrinter:(Printer *) print andTarget:(id<Printable>) targ {
if((self = [super init])) {
printer = print;
self.target = targ;
}
return self;
}
- (void) start {
[target print:printer]; //invoke print on the target, which we know conforms to Printable
}
- (void) dealloc {
[target release];
[super dealloc];
}
#end
I think you need to understand the Delegate Pattern. It is a core pattern used by iphone/ipad applications and if you don't understand it you will not get far. The link to wikipedia I just used outlines the pattern and gives examples of it's use including Objective C. That would be a good place to get started. Also look at take a look at the Overview tutorial from Apple which is specific to the iPhone and also discusses the Delegate pattern.

Resources