Is it possible to, say, use a block as a completion handler in a View Controller's init method so that the parent view controller is able to fill in the details in a block without having to create a custom initWithNibName:andResourceBundle:andThis:andThat: for each possible properties ?
// ... in the didSelectRowAtIndexPath method of the main view controller :
SubViewController *subviewController = [[SubViewController alloc] initWithNibName:nil bundle:nil completionHandler:^(SubViewController * vc) {
vc.property1 = NO;
vc.property2 = [NSArray array];
vc.property3 = SomeEnumValue;
vc.delegate = self;
}];
[self.navigationController pushViewController:subviewController animated:YES];
[subviewController release];
in SubViewController.m :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completionHandler:(void (^)(id newObj))block {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
block(self);
}
return self;
}
instead of
// ... in the didSelectRowAtIndexPath method of the main view controller :
SubViewController *subviewController = [[SubViewController alloc] initWithNibName:nil bundle:nil andProperty1:NO andProperty2:[NSArray array] andProperty3:SomeEnumValue andDelegate:self];
[self.navigationController pushViewController:subviewController animated:YES];
[subviewController release];
with
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andProperty1:(BOOL)p1 andProperty2:(NSArray *)p2 andProperty3:(enum SomeEnum)p3 andDelegate:(id<MyDelegateProtocol>)myDelegate {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.property1 = p1;
self.property2 = p2;
self.property3 = p3;
self.delegate = myDelegate;
}
return self;
}
So that I can do whatever I want in the main controller vs calling a predefined init method (and having to write one for each possible initialization).
Is it something bad ? will there be retain cycles ?
Which advantages do you see in using a block? The initializer is commonly used to set up private state of the instance. This private state could not be accessed from the block since the block is implemented somewhere else.
If you only use public properties why not setting them up after initialization?
SubViewController *vc = [[SubViewController alloc] initWithNibName:nil bundle:nil];
vc.property1 = NO;
vc.property2 = [NSArray array];
vc.property3 = SomeEnumValue;
vc.delegate = self;
That's exactly what the block version does (without the hassle).
Is it something bad ? will there be retain cycles ?
No, but I would dismiss your proposition for architectural reasons: You are either breaking encapsulation of the class or do not gain any advantage over just doing what the block does after initialization.
The questions are:
Be aware that when program is growing new levels of invocation will be added and this will make your code hard to read, maintain, extend or develop. Think about future subclassing as well and how will you debug this code in the future to find some mismatched value. Blocks can make you code faster, but delegate pattern will make your code clean and run in one thread, which is easy to maintain in the future, and this is real value for the professional programmer.
You could define your
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completionHandler:(void (^)(id newObj))block;
method in a category of UIViewController
; from there you would call initWithNib
and then execute your completion block on the just allocated self
:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil completionHandler:(void (^)(id newObj))block
{
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
block(self);
}
return self;
}
I think this should work fine.
This is possible, no retain
problems. Everything will be called synchronously on the same thread.
BUT
What is the benefit of not doing this the simple way - calling another method after init
, e.g.
MyController* controller = [[[MyController alloc] init] autorelease];
[self updateController:controller];
Does the code have be called from the init
method?
In general, I would advice to create separate init...
methods if you want to initialize the object in different ways.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With