iOS Blocks - use of undeclared identifier self - iphone

I am new to blocks. I am inside a singleton and I do this
void (^ myBlock)() = ^(){ [self doStuff]; };
I receive this error use of undeclared identifier self.
doStuff is a method inside the singleton.
but if this block is declared inside another method, Xcode is OK.
Why is that? thanks.

you can define the block in your interface and initialize in any of your methods (including initializers ) in your #implementation file like below:
#interface YourClass {
void (^ myBlock)();
}
#implementation YourClass
- (void)yourMethod {
myBlock = ^(){ [self doStuff]; };
}
#end

You shouldn't call self directly in a block.
Rather you should make a safe block-pointer from self and access it inside your block.
__block id safeBlockSelf = self;
void (^ myBlock)() = ^(){ [safeBlockSelf doSomething]; };
See How do I avoid capturing self in blocks when implementing an API? for more details.

because every method gets passed self as a hidden param. self is a variable like any other and the block can 'see it/capture it' if in the method
if it is not in a method, self is not a variable set anywhere and the block cant 'see it'

Related

What is Best practice in objective c for creating an object and setting its properties

Considering I have a UIViewController called ErrorViewController that I am instantiating using initWithNibName.
There is a enum on this ErrorViewController describing its "type".
This ErrorViewController has one delegate function that returns to its delegate which will respond according to the type set on the ErrorViewController.
Is it better to pass all the parameters within a new initWithNibName function, and set private properties on the ErrorViewController. Like this:
ErrorViewController *errorVc = [[ErrorViewController alloc]
initWithNibName:#"ErrorViewController" bundle:nil
andErrorType:kErrorTypeA andDelegate:self];
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
andErrorType:(ErrorType)errorType andDelegate:(id<ErrorDelegate>)delegate{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = delegate;
self.errorType = errorType;
}
return self;
}
Or is it better to instantiate the object and afterward set its public properties like this:
ErrorViewController *errorVc = [[ErrorViewController alloc]
initWithNibName:#"ErrorViewController" bundle:nil];
errorVc.delegate = self;
errorVc.type = kErrorTypeA.
And regarding the delegate method, is it best practice to check the type by passing a parameter, or by checking the property of the passed back Controller as follows:
- (void)ErrorPage:(ErrorViewController *)ErrorPage
// check ErrorPage.errorType
}
or this: ?
- (void)ErrorPage:(ErrorViewController *)ErrorPage
andErrorType:(ErrorType)errorType
// check errorType
}
I think it's a question of preference. If the object can't function correctly without error-type and/or delegate, it's probably best to provide your custom initialiser.
As to your second question, I would provide the error type as in your second example. Note that the method name should start with a lowercase character though (-errorPage: instead of -ErrorPage:).
Additionally, if you use it a lot, I would provide a convenience class method to create the object:
+(ErrorViewController*) standardErrorViewControllerWithErrorType: (ErrorType) errorType andDelegate: (id<ErrorDelegate>) delegate {
ErrorViewController *evc = [[ErrorViewController alloc] initWithNibName: #"ErrorViewController" bundle: nil andErrorType: errorType andDelegate: delegate];
return evc;
}
Edit
Also, in your init method, it is encouraged to use -(instancetype) init... instead of -(id) init....

Calling a method which executes delegate methods

I have a view controller called myViewController. Then i have an NSObject called myLogic. myLogic has a method called executeLogic() which will call some delegate methods. (Im guessing the delegate methods are called in separate threads). I am calling executeLogic() from myViewController and i want it to execute all the delegate methods before returning to execute the next command on myViewController. Right now i get this error
[URLRequestDBStoreLogic respondsToSelector:]: message sent to deallocated instance 0x5d2cff0
which i am guessing is because it returns to the main thread before the delegate methods are called? I am not sure. Any solutions? Will be deeply grateful. :)
This is where the URLRequestDBStoreLogic class is called (note this is an NSObject Class)
URLRequestDBStoreLogic * urlRequestLogicDBStoreLogic = [[URLRequestDBStoreLogic alloc]init];
[urlRequestLogicDBStoreLogic loadObjectsAtRemoteServer];
This is what the method that is called does
- (void) loadObjectsAtRemoteServer {
RKURL * url = [RKURL URLWithBaseURLString:#"http://y.co.uk/share/proxy/alfresco/slingshot/search?site=&term=&tag=x&maxResults=251&sort=&query=&repo=false"];
objectManager = [RKObjectManager managerWithBaseURL:url];
//Some other Code
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"?tag=x" delegate:self];
}
and this is where it breaks in the if statement.
// Setup the NSURLRequest. The request must be prepared right before dispatching
- (BOOL)prepareURLRequest
{
[_URLRequest setHTTPMethod:[self HTTPMethod]];
if ([self.delegate respondsToSelector:#selector(requestWillPrepareForSend:)]) {
[self.delegate requestWillPrepareForSend:self];
}
}

MainViewController init

I have set up a utility application and I found that the init method of MainViewController is not called automatically. Is there some other method that is set up automatically by XCode for initialization? Or if I have to add it, where would I add it? I was just going to call init manually from an IBOutlet method but I would prefer that the initializations be done when the view is first initialized.
Not sure where you'r going but (generated) .xib files are called using the withCoder init.
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
//self implementation
}
return self;
}
See the Utility Template in Xcode.
And check this method called..
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];
}
check it..

Creating constructors in Objective-C

Why do we always do this when creating constructors in Objective C?
self = [super init];
if ( self ) {
//Initialization code here
}
you can create constructor and destructor in objective-c with
-(id) init
{
self = [super init];
if(self)
{
//do something
}
return self;
}
-(void) dealloc
{
[super dealloc];
}
We reassign to self because [super init] is allowed to return a different object than the one it was called on. We if (self) because [super init] is allowed to return nil.
self is a class based on some superclass (e.g. UIViewController, NSObject - see your interface file to be sure which one). The superclass might need some form of initialization in order for the subclass to work as expected. So by first initializing the superclass we make sure default properties and the like are set. Without initializing the superclass first, we might experience some very unexpected behavior, especially in more complex objects like ViewControllers and the like.
Read this apple document on initialization
http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/ObjectiveC/Chapters/ocAllocInit.html

Strange custom delegate actions

Ok -- this one is weird. I have a singleton class that loads information from an XML file. I am using a delegate definition as follows (I define the delegate in a separate header file to make life easier):
#protocol ResourceClassDelegate <NSObject>
#optional
- (void)picturesDidStartLoading;
- (void)picturesDidFinishLoading;
#end
In the resource file, the delegate is defined correctly (I believe):
#property (assign) id<ResourceClassDelegate> delegate;
When using the delegate, the code in the resource class is as follows:
-(void)refreshPiecesOfHistoryWithOperation {
NSLog(#"Operation Started");
if ([delegate respondsToSelector:#selector(picturesDidStartLoading)])
[delegate picturesDidStartLoading];
self.picturePacks = [HistoryXMLParser loadPicturePacks];
[self.allPiecesOfHistory removeAllObjects];
// now lets put all of them in one big file...
for (PicturePack *pp in self.picturePacks) {
for (int ct = 0; ct < [[pp piecesOfHistory] count] ; ct++) {
[self.allPiecesOfHistory addObject:(PieceOfHistory *)[[pp piecesOfHistory] objectAtIndex:ct]];
}
}
NSLog(#"Operation Ended");
if ([delegate respondsToSelector:#selector(picturesDidFinishLoading)])
[delegate picturesDidFinishLoading];
}
Now... in the class that is listening to the delegate, it is assigned:
- (void)viewDidLoad {
[super viewDidLoad];
// now for the part that makes the loading all happen...
[[ResourceClass sharedResourceClass] setDelegate:self];
}
And in the listening class, the methods are defined....
#pragma mark ResourceClassDelegate
-(void)picturesDidStartLoading {
if (loadingActivity == nil)
loadingActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[self.view addSubview:loadingActivity];
[loadingActivity setCenter:[self.view center]];
[loadingActivity startAnimating];
}
-(void)picturesDidFinishLoading {
if (loadingActivity != nil) {
[loadingActivity stopAnimating];
[loadingActivity removeFromSuperview];
}
[self.tableView reloadData];
}
Now for the problem... every single time, in the listening class, the method (void)picturesDidFinishLoading is called. The method (void)picturesDidStartLoading never is called.
When I debug the code, in the resource class, the line
if ([delegate respondsToSelector:#selector(picturesDidStartLoading)])
[delegate picturesDidStartLoading];
never reaches the delegate method call - even if I remove the if statement. The line
if ([delegate respondsToSelector:#selector(picturesDidFinishLoading)])
[delegate picturesDidFinishLoading];
is always called.
any ideas?
Ok -- I figured it out....
The delegate was nil during the first call. The reason it is nil is because the function using the delegate was called in the source during the init method. The init method was not complete when the first test of the delegate was performed. At this time the delegate was nil because it is not instantiated until the the init method completes. The reason the second test of the delegate worked is because I submitted the process using an NSOperationQueue.
To fix the problem I have to move things around a bit... it's all about the timing!
Well now that was fun....
That's weird, try to remove #optional in the protocol declaration, and see if you get some warnings.
Try to print a log inside the method as well, other than that it looks fine.