Preventing a crash if a block is nil without thousands of ifs - objective-c

I love using blocks. I constantly create custom classes that use blocks to communicate with callers instead of delegate mechanisms.
But the problem is that these classes got polluted with checks to see if the block was declared before running them. Something like:
if (self.onExit) {
self.onExit(flag);
}
obviously I cannot omit the if or the code will crash if _onExit is nil;
Is there something I can create, a category or something, that will allow me to just run the block directly without the thousands of ifs but will internally check for nil before running it?

What about a macro like this?
#define BLOCK_SAFE_RUN(block, ...) block ? block(__VA_ARGS__) : nil
This is from another answer with more details here: https://stackoverflow.com/a/13037198/747339

rmaddy suggested this in a comment and I followed up with an example: a little bit of refactoring might be the way to go here. Put the null-check-and-call into a method. Then call the method unconditionally wherever you have the conditional call of the Block.
Something like this:
#interface MyClass : NSObject
#property (copy, nonatomic) void (^onExit)(BOOL);
#end
#interface MyClass ()
- (void)performExit:(BOOL)flag;
#end
#implementation MyClass
- (void)performExit:(BOOL)flag
{
if( self.onExit ){
self.onExit(flag);
}
}
- (void)doThatThing
{
// Replace
// if( self.onExit ){
// self.onExit(flag);
// }
// with
[self performExit:YES];
// everywhere.
}
#end

Related

Objective C class method error ''Use of undeclared identifier"

Hopefully not a ridiculous question as I'm a self taught programmer, but I found some code which looked like it might help me do something I wanted to. Basically I want to enhance the NSLog() function in one of my apps, and would like to call my method in the same way as NSLog(). It's very difficult to google 'void function()' because nothing seems to be relevant, I'm used to methods that are constructed like this:
-(void)RLog(NSString*)statement;
But the sample suggested using:
void RLog(NSString *statement,...);
This seems to work, and lets me call it with 'RLog(#"My message")', however using it this way the method ignores the class variables, and seems I can't use 'self' either ...
Logging.h
#import <UIKit/UIKit.h>
#import Foundation.NSString;
#interface Logging : NSObject
#property (nonatomic) BOOL enabled;
void RLog(NSString *statement,...);
#end
Logging.m
#import "Logging.h"
#implementation Logging
#synthesize enabled;
void RLog(NSString *format,...) {
/* something that uses 'enabled' throws 'Use of undeclared identifier enabled' */
/* something else that uses '[[self class] session]' throws 'Use of undeclared identifier self' */
}
#end
Hopefully I've included enough information to explain my issue, and not removed too much to make it hard to understand!
Thanks in advance.
Plasma
void RLog(NSString *format,...)
... is not an Objective-C method; it's just a C function.
C functions are global and free-standing. There is no self here and no connection with Logging's enabled. As far as this function is concerned, the Logging class might as well not exist at all.
After a bit more investigation I found a way around this using the information here.
I added a class variable called thisClass and then assigned 'self' to it during my class init stage.
#implementation Logging
id thisClass;
- (id) init
{
if (self = [super init])
{
thisClass = self;
}
return self;
}
From inside the C function I can now call methods in my Logging class using:
[thisClass log:#"Testing"];
Without having to send "self" in as a parameter, I've moved the rest of the code which needs the local variables in to my 'log' method and simply use the C method to call it in a simplified way.
Plasma

How to write methods that should only be used within the class itself and are able to access ivars [duplicate]

This question already has answers here:
Best way to define private methods for a class in Objective-C
(12 answers)
Closed 9 years ago.
I have a class which has some methods that are only to be used within the class itself. These methods exist because I have a three-step process for the graphics work I'm doing, but I only want instances of the class to access the final result of those calculations, in a simplified example:
#import <Foundation/Foundation.h>
#interface GraphicsWorld : NSObject
#property(nonatomic, strong) NSMutableArray *objects;
#property(nonatomic, strong) NSMutableArray *adjustedObjects
/* three methods I'll never use outside of this class
I want to find a way to get replace these methods.
*/
-(void) calcTranslation;
-(void) calcRotation;
-(void) calcPerspective;
/* the one method I'll use outside of this class */
-(NSMutableArray *) getAdjustedObjects;
#end
I could define c-functions just outside of my implementation for this, but then they wouldn't have access to the properties:
#import <Foundation/Foundation.h>
#import "GraphicsWorld.h"
void calcTranslation()
{
// I'm useless because I can't access _objects.
}
void calcRotation()
{
// Hey, me too.
}
void calcPerspective()
{
// Wow, we have a lot in common.
}
#implementation GraphicsWorld
-(NSMutableArray *) getAdjustedObjects
{
calcTranslation();
calcRotation();
calcPerspective();
return adjustedObjects;
}
#end
Unless I'm misunderstanding your question, it sounds like you just want to hide your methods from being public? If so, just delete them from the header. You no longer need to declare methods in advance in objc (Xcode). The compiler will just find them internally now.
Make C-style functions (as you've shown) that take arguments and return values.
Make private Objective-C-style methods.
In addition to your #implementation section in the .h file, you can also have one in your .m file, which is private. Just as you declare methods and properties in the .h file's #implementation, you can do the same in the .m.
A method can be called whether it is declared private, or not put in the header file; due to the nature of Objective-C hiding methods is hard.
Hiding functions is a lot easier, just declare them static. To access the current instance you just pass in a reference to it - i.e. exactly what Objective-C does behind the scenes.
So for example:
void calcTranslation(GraphicsWorld *self)
{
// Access properties, instance variables, call instance methods etc.
// by referencing self. You *must* include self to reference an
// instance variable, e.g. self->ivar, as this is not a method the
// self-> part is not inferred.
}
and to call it:
-(NSMutableArray *) getAdjustedObjects
{
calcTranslation(self);
...

Is it possible to override property's method?

I need to add some codes when MyClass's string value is changed.
So I'm trying to override a MyClass's string property method.
But I have no idea.. so I do like following.
Is it correct?
How to override property's method?
#interface MyClass{
NSString *string;
}
#property(retain, nonatomic) NSString *string;
#end
#implementation MyClass
- (void)setString:(NSString*)newString{
// want to add some codes.
[self setString:newString]; <= Is this correct?
}
#end
- (void)setString:(NSString*)newString{
// want to add some codes.
string = newString; //This is the setter method!
// You will need to consider memory management etc.
}
What you are probably more up to is this:
- (void)setString:(NSString*)newString{
// want to add some codes.
[super setString:newString];
}
[self setString:newString] at this place would be a an endless recursive loop. [super setString:newString] should call the superlass' setter. However, I never did that myself.
What you are trying to do is not to override (no subclass are involve in your code snippet).
What is in your code is just the declaration #interface and the definition #implementation. It have the same meaning and utility to the declaration/definition in C where you put declaration in a .h file and definition in a .c file.
Assuming that your are speaking of how to synthesize, your code is almost correct. You are just missing the getter - (NSString *) string; or you what it readonly.
As for how to do correctly the assignment you should use the =
- (void)setString:(NSString*)newString{
// want to add some codes.
string = newString; // Correct way of doing it
}
There is 2 way to synthesize a propertie, either by defining the setter and getter by hand or either by using the syntactic sugar #synthesize.
For a better understanding consider that #property and #synthesize are both syntactic sugar. (Only that #property is adding some semantic with the retain, strong, etc.. keyword).
Better is to read the documentation that you can found. There is many easy to found web page where you could have more details.

Is it possible to extend an existing Objective-C Block?

I have a class using a Block defined in the header like this:
#property (readwrite, copy) RequestSucceededBlock succeededBlock;
The property succeededBlock is already set with a Block. Is there a way to override this Block with another that still calls the original, similar to class inheritance?
I assume this is not possible, because class inheritance should be used to express things like that. Is it still possible?
Assuming you're talking about trying to have a replacement block in a subclass that still calls the superclass block, you can't inject a block into an existing block but you can fake it as follows:
// in MySubclass.h
#property (nonatomic, copy) RequestSucceededBlock subclassSucceededBlock;
// in MySubclass.m
- (RequestSucceededBlock)succeededBlock
{
[return subclassSucceededBlock];
}
- (void)setSucceededBlock:(RequestSucceededBlock)newSucceededBlock
{
// make sure this conforms to the definition of RequestSucceededBlock
RequestSucceededBlock combinedBlock = ^{
dispatch_async(dispatch_get_current_queue(), newSucceededBlock);
dispatch_async(dispatch_get_current_queue(), [super succeededBlock]);
};
subclassSucceededBlock = combinedBlock;
}
This is a bit odd though b/c it assumes the superclass has a default block assigned to succeededBlock that you want to dispatch. If your question has a different use in mind please clarify and I'll see if I can update this.
EDIT: added copy to iVar

ViewController may not respond to'method' problem

I know it is a common problem, I googled a lot and seems get no luck to solve my problem.
I have a #interface TestViewController:UIViewController
and in its implementation file I have a method defined:
-(void)method1 {
do something;
[self method1];//here I need to call the method itself if a statement is true and this line is where the warning TestViewController may not respond to'method1' I got
}
-(void)method2{
[self method1] //But there is no problem with this line
}
Can anyone help me?
Thanks in advance!
Your method declarations are missing in the header.
Just add
-(void)method1;
-(void)method2;
to your TestViewController.h file
Update:
The reason why you don't get a warning about the second call ([self method1] within method2) is, that the compiler already knows about method1 at that point. (because the implementation occurs before method2)
Objective-C just as C uses a single pass compiler to gather all known symbols. The result is that you can only reference methods and variables that has been declared above the current scope.
You can solve this particular problem you give an example of in three ways:
Add method1 to the public interface in the header file, just as #weichsel suggested.
If you want method1to be private then you can add it to your class by declaring an unnamed category at the top of you implementation file. Like this:
#import "Foo.h"
#interface Foo ()
-(void)method1;
#end
#implementation Foo
// ... lots of code as usual ...
#end
The third option could be regarded as hack by some, but it really a feature of the Objective-C language. Just as all methods get an implicit variable named self that is the instance the method was called on, so do all method alsa get the implicit variable named _cmd, that is of type SEL, it is the selector that was used to call this method. This can be used to quickly call the same method again:
-(void)method1 {
if (someContition) {
[self performSelector:_cmd withObject:nil];
} else {
// Do other stuff...
}
}
This is most useful if you want to make sure that a particular method is always performed on the main thread:
-(void)method {
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];
return;
}
// Do stuff only safe on main thread
}