Hello everyone i am new to objective c. The following code is not mine. I am just trying to understand how it works. I have a ViewController that has this property in the .h file.
#property (nullable, nonatomic, copy) dispatch_block_t logHandler;
Inside the .m file the logHandler is called when a button is pressed with the following code.
- (IBAction)login:(id)sender {
if (nil != self.logHandler) {
self.logHandler();
}
}
Then the logHandler is called which exists in another class NSObject file
inside the .h file
#interface LogFlow : NSObject<TheFlowController>
#end
and in .m file
- (UIViewController *)rootViewController {
LogViewController *viewController = LogViewController.newInstance;
viewController.logHandler = ^{
UIViewController *logController = [self startNewLogFlow];
[self.navigationController pushViewController:logController animated:YES];
};
return viewController;
}
I do not understand why the logHandler exists in another class and why it is called from this specific class, and how is it possible to call this code from another class without any import used? I am trying to understand when to use this kind of implementation and how to use it. Any help appreciated.
The construct that you see in the rootViewController:
^{
UIViewController *logController = [self startNewLogFlow];
[self.navigationController pushViewController:logController animated:YES];
};
This is what's known as a "Block" in Objective-C. You may find other references to it in other languages as an "anonymous function" or a "closure". Those names apply here as well.
This creates an object that is just a function, but the function doesn't have a name. You can also assign the unnamed function to variables and call it from the variable - which is what happens here. The anonymous function, the block, is assigned to the logHandler instance variable of the viewController object. Later some other code can call that function through the variable as you see in your login: example.
Here's a simpler block that is just plain Objective-C:
int squareFunction(int x) {
return x * x;
}
void playWithSquares(void);
void playWithSquares(void) {
int nine = squareFunction(3);
int alsoNine = (^(int x){
return x * x;
})(3);
}
The declaration of squareFunction creates a named function that calculates the square of two integers.
You also see the the expression:
^(int x){
return x * x;
};
This also creates a function that calculates the square of an integer, but it doesn't bind that function to a name. Since it has no name we call the function immediately by wrapping it in parenthesis and then passing it arguments (<anonymous function expression>)(3)
We could store the anonymous function in a variable:
typedef int (^SquaresBlock)(int);
SquaresBlock myBlock = ^(int x){
return x * x;
};
and then call it later using squaresBlock(3)
Blocks are very important in Cocoa's use of Objective-C so you should learn more about them.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html
Related
Upon receiving an NSString, I would like to call a specific code block. I figured an NSDictionary would be best for associating these. Simplified, I'm using something like:
MyProtocol.h:
#protocol MyProtocol <NSObject>
typedef void (^Handler)(id<MyProtocol> obj, id data);
#end
MyClass.h:
#interface MyClass : NSObject <MyProtocol>
- (void)aMethodWithString:(NSString *)string andData:(id)data;
#end
MyClass.m:
#interface MyClass ()
void myCommandHandler(id<MyProtocol> obj, id data); // matches signature defined in protocol
#end
#implementation MyClass
void myCommandHandler(id<MyProtocol> obj, id data)
{
// ...
}
- (void)aMethodWithString:(NSString *)string andData:(id)data
{
static NSDictionary<NSString *, Handler> *handler;
static dispatch_once_t onceToken;
// don't allocate this dictionary every time the function is called
dispatch_once(&onceToken,
^{
handler =
#{
#"MyCommand":myCommandHandler,
};
});
// ... error checking, blah blah ...
Handler block;
if ((block = handler[string]))
{ block(self, data); }
}
#end
Using this, I get an error in the dictionary literal construction:
Collection element of type 'void (__strong id<MyProtocol>, __strong id)' is not an Objective-C object`
So how can I include a C function or block reference in the dictionary? There will be quite a few larger complex functions to be defined, so it would be very much preferred to not have all of them defined inside the dictionary literal itself (a technique I know will work).
--
Also, I'm not sure what's considered proper style here: (1) I originally had the dictionary declaration outside of any method body at the file scope (without the dispatch_once(...)) which generates the same error, but I thought maybe it would be easier for others to see what's going on by (2) including it in the only method that uses that dictionary. Is one style preferred over the other for any reason?
Your Handler type is a block type, not a function pointer type. If you had declared it using * instead of ^, it would be a function pointer type.
Your myCommandHandler function is, of course, a function, not a block. Your comment is wrong. It does not match type Handler.
Function pointers are not Objective-C object pointers. Functions are not objects. Blocks are Objective-C objects, but you're not actually using any blocks here. (You've just declared a typedef for one, but you're not actually using it.)
You could use blocks and store them in your dictionary. The blocks could either contain the desired code or call a function or method which does.
A C function address is not an Objective-C object, and an NSDictionary can only store the latter.
A C function address is just a pointer, to wrap a C pointer as an object you use NSValue and its class method valueWithPointer.
To get the pointer value back from the NSValue object you use the instance method pointerValue. Before you can use the extracted pointer you must cast it to your function type.
HTH
My code invokes a C library function:
#implementation Store
...
-(void) doWork {
// this is a C function from a library
int data = getData();
...
}
end
I am unit testing the above function, I want to mock the C function getData() in my test, here is my test case:
#interface StoreTests : XCTestCase {
int mData;
Store *store;
}
#end
#implementation StoreTests
-(void) setUp {
[super setUp];
mData = 0;
store = [[Store alloc] init];
}
-(void) testDoWork {
// this call will use the mocked getData(), no problem here.
[store doWork];
}
// mocked getData()
int getData() {
mData = 10; // Use of undeclared identifier 'mData', why?
return mData;
}
...
#end
Why I get complier error:
Use of undeclared identifier 'mData' inside mocked getData() function?
You are misunderstanding how instance methods and variables work.
Every instance method has a variable self which references the current instance (or "current object") and a use of an instance variable, such as mData, is shorthand for accessing that variable using self, e.g self->mData, where -> is the (Objective-)C operator for field access. So your setup method written "long hand" is:
-(void) setUp {
[super setUp];
self->mData = 0;
self->store = [[Store alloc] init];
}
But where does self, the reference to the instance, itself come from? Well it's not magical, just hidden, it is passed to an instance method automatically as a hidden extra argument. At this point which switch to pseudo-code to show this. Your setup method is effectively compiled as:
-(void) setUp withSelf:(StoreTest *)self {
[super setUp];
self->mData = 0;
self->store = [[Store alloc] init];
}
and a call such as:
StoreTests *myStoreTests = ...
[myStoreTests setup];
is effectively compiled as something like:
[myStoreTests setup withSelf:myStoreTests];
automatically adding the extra self argument.
Now all the above only applies to methods, and enables them to access instance variables and methods, it does not apply to plain C functions - they have no hidden self argument and cannot access instance variables.
The solution you mention in the answer you added of declaring mData outside of the interface:
int mData;
#interface StoreTests : XCTestCase {
Store *store;
}
#end
changes mData into a global variable, instead of being an instance variable. C functions can access global variables. However this does mean that every instance of the class shares the same mData, there is only one mData in this case rather than one for every instance.
Making an instance variable into a global is therefore not a general solution to to issues like this, however as it is unlikely that you will have more than one instance of your StoreTests class it is a suitable solution in this case.
You should however make one change: you can only have one global variable with a given name with a program, so your mData must be unique and is accessible by any code within your program, not just the code of StoreTests. You can mitigate this my declaring the variable as static:
static int mData;
this keeps the variable as global but only makes it visible to code within the same file as the declaration, which is probably just the code of StoreTests.
HTH
I found one solution for my question, that is declare mData above #interface StoreTests : XCTestCase, something like this:
int mData;
#interface StoreTests : XCTestCase {
Store *store;
}
#end
...
If I want to access a variable that is declared in Class A and I
want to use that variable in Class B .
I don't want to use Property.
How Can I do ?
It is bad practice to declare a public variable without making it a property.
You may also use KVC to access(both read and write) ivar, even if it is readonly.
[instanceOfMyClass valueForKey:#"myIvar"];
I hope someone finds my first stackOverflow answer helpful :)
#interface Class1
{
#public
int var; // if you not declare it public by default it'll be protected
}
// methods...
#end
// Inside a Class2 method:
Class1 *obj = ...;
obj->var = 3;
But property approach is far better.
Well, you can declare variable as public and access it with selector operator, but this is not recommended:
#interface A:NSObject{
#public
int x;
}
#end
...
//Somewhere inside class B
A *a = [[A alloc] init];
a->x;
However it's hard to imagine why it can be better that to use a property.
The 4 possibles cases that I can think to access a variable are:
1 Declare the variable in class A as public
#public
BOOL _test;
Totally not recommended. If you need a public variable you use a property.
2 Use a property.
#property (readonly, getter = myMehtodName) id myVariable;
3 Use a custom method. In practice it acts the same as a property with readonly attribute. Also you can access it with the dot notation.
4 Use KVC to access the variable.
This can be useful when you don't know the name of the property / variable in compilation time.
A little example:
NSString *myKey = [self obtainKey];
id myVariable = [self valueForKey:myKey];
if ([myVariable isKindOfClass:[NSString class]]) {
//Do something
}else {
//Do another thing
}
Note that key can be either a method name or a variable.
Is is possible to create getters and setters for constants? I want to refer to a constant directly, and have it instantiate itself if it's value is nil. A constant declared like this:
// Prefs.h
extern MyClass * const kThing;
// Prefs.m
MyClass * const kThing = nil;
and the getter/setter would look like:
// getter
+ (MyClass *)kThing
{
_kThing = _kThing ? : [MyClass new];
return _kThing;
}
// setter
+ (void)setKThing:(MyClass *)myClass
{
_kThing = myClass
}
And then I could use it like:
[kThing doSomething];
Is this possible?
edit edited the methods to class methods
What you describe are not constants, they are global variables. You cannot define getters and setters for them, but you can use their values to back class methods, which is precisely what you have done.
However, when you send message like this
[kThing doSomething];
the global variable is used directly, bypassing your getter. If you want to go through a getter, you can write
[[MyClass kThing] doSomething];
or inside methods of MyClass you can write
[[[self class] kThing] doSomething];
Another note is that when yo implement accessor methods like that, you should make the backing variables static, rather than extern. This will ensure that other modules cannot access these variables bypassing your getters.
Global variable declaration in other file is very dangerous in objective C. Ideally we use sharedInstance. Try like this:
In MyGame.h
#interface MyGame : NSObject
{
int mScore;
}
#property(nonatomic,assign) int score;
+(MyGame*)sharedObject;
-(void)someFunction;
#end
In MyGame.m
static MyGame *gGame = nil;
#implementation MyGame
#synthesize score = mScore;
+(MyGame*)sharedObject
{
if(!gGame)
{
gGame = [[MyGame alloc] init];
}
return gGame;
}
-(void)someFunction
{
}
#end
To access anywhere in project:
#import "MyGame.h"
[MyGame sharedObject].score;
[MyGame sharedObject] someFunction];
The short answer is that this is not possible.
MyClass * const kThing = nil;
means that kThing is a constant pointer, which means that the address in memory that it points to cannot be changed. So once it's set to nil, it can't later be set to a new object.
Is it possible to have blocks as properties using the standard property syntax?
Are there any changes for ARC?
#property (nonatomic, copy) void (^simpleBlock)(void);
#property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);
If you are going to be repeating the same block in several places use a type def
typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
#property (nonatomic) MyCompletionBlock completion;
Here's an example of how you would accomplish such a task:
#import <Foundation/Foundation.h>
typedef int (^IntBlock)();
#interface myobj : NSObject
{
IntBlock compare;
}
#property(readwrite, copy) IntBlock compare;
#end
#implementation myobj
#synthesize compare;
- (void)dealloc
{
// need to release the block since the property was declared copy. (for heap
// allocated blocks this prevents a potential leak, for compiler-optimized
// stack blocks it is a no-op)
// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.
[compare release];
[super dealloc];
}
#end
int main () {
#autoreleasepool {
myobj *ob = [[myobj alloc] init];
ob.compare = ^
{
return rand();
};
NSLog(#"%i", ob.compare());
// if not ARC
[ob release];
}
return 0;
}
Now, the only thing that would need to change if you needed to change the type of compare would be the typedef int (^IntBlock)(). If you need to pass two objects to it, change it to this: typedef int (^IntBlock)(id, id), and change your block to:
^ (id obj1, id obj2)
{
return rand();
};
EDIT March 12, 2012:
For ARC, there are no specific changes required, as ARC will manage the blocks for you as long as they are defined as copy. You do not need to set the property to nil in your destructor, either.
For more reading, please check out this document:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html
#property (copy)void
#property (copy)void (^doStuff)(void);
The actual Apple documentation which states precisely what to use:
Apple doco.
Your .h file:
// Here is a block as a property:
//
// Someone passes you a block. You "hold on to it",
// while you do other stuff. Later, you use the block.
//
// The property 'doStuff' will hold the incoming block.
#property (copy)void (^doStuff)(void);
// Here's a method in your class.
// When someone CALLS this method, they PASS IN a block of code,
// which they want to be performed after the method is finished.
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;
// We will hold on to that block of code in "doStuff".
Your .m file:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{
// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;
// Now do other processing, which could follow various paths,
// involve delays, and so on. Then after everything:
[self _alldone];
}
-(void)_alldone
{
NSLog(#"Processing finished, running the completion block.");
// Here's how to run the block:
if ( self.doStuff != nil )
self.doStuff();
}
Beware of out-of-date example code.
With modern (2014+) systems this is the correct and documented approach.
For posterity / completeness's sake… Here are two FULL examples of how to implement this ridiculously versatile "way of doing things". #Robert's answer is blissfully concise and correct, but here I want to also show ways to actually "define" the blocks.
#interface ReusableClass : NSObject
#property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
#end
#implementation ResusableClass
static NSString const * privateScope = #"Touch my monkey.";
- (CALayer*(^)(NSArray*)) layerFromArray {
return ^CALayer*(NSArray* array){
CALayer *returnLayer = CALayer.layer
for (id thing in array) {
[returnLayer doSomethingCrazy];
[returnLayer setValue:privateScope
forKey:#"anticsAndShenanigans"];
}
return list;
};
}
#end
Silly? Yes. Useful? Hells yeah. Here is a different, "more atomic" way of setting the property.. and a class that is ridiculously useful…
#interface CALayoutDelegator : NSObject
#property (nonatomic,strong) void(^layoutBlock)(CALayer*);
#end
#implementation CALayoutDelegator
- (id) init {
return self = super.init ?
[self setLayoutBlock: ^(CALayer*layer){
for (CALayer* sub in layer.sublayers)
[sub someDefaultLayoutRoutine];
}], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
self.layoutBlock ? self.layoutBlock(layer) : nil;
}
#end
This illustrates setting the block property via the accessor (albeit inside init, a debatably dicey practice..) vs the first example's "nonatomic" "getter" mechanism. In either case… the "hardcoded" implementations can always be overwritten, per instance.. a lá..
CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
[layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;
Also.. if you want to add a block property in a category... say you want to use a Block instead of some old-school target / action "action"... You can just use associated values to, well.. associate the blocks.
typedef void(^NSControlActionBlock)(NSControl*);
#interface NSControl (ActionBlocks)
#property (copy) NSControlActionBlock actionBlock; #end
#implementation NSControl (ActionBlocks)
- (NSControlActionBlock) actionBlock {
// use the "getter" method's selector to store/retrieve the block!
return objc_getAssociatedObject(self, _cmd);
}
- (void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject( // save (copy) the block associatively, as categories can't synthesize Ivars.
self, #selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self; // set self as target (where you call the block)
self.action = #selector(doItYourself); // this is where it's called.
}
- (void) doItYourself {
if (self.actionBlock && self.target == self) self.actionBlock(self);
}
#end
Now, when you make a button, you don't have to set up some IBAction drama.. Just associate the work to be done at creation...
_button.actionBlock = ^(NSControl*thisButton){
[doc open]; [thisButton setEnabled:NO];
};
This pattern can be applied OVER and OVER to Cocoa API's. Use properties to bring the relevant parts of your code closer together, eliminate convoluted delegation paradigms, and leverage the power of objects beyond that of just acting as dumb "containers".
Of course you could use blocks as properties. But make sure they are declared as #property(copy). For example:
typedef void(^TestBlock)(void);
#interface SecondViewController : UIViewController
#property (nonatomic, copy) TestBlock block;
#end
In MRC, blocks capturing context variables are allocated in stack; they will be released when the stack frame is destroyed. If they are copied, a new block will be allocated in heap, which can be executed later on after the stack frame is poped.
Disclamer
This is not intended to be "the good answer", as this question ask explicitly for ObjectiveC. As Apple introduced Swift at the WWDC14, I'd like to share the different ways to use block (or closures) in Swift.
Hello, Swift
You have many ways offered to pass a block equivalent to function in Swift.
I found three.
To understand this I suggest you to test in playground this little piece of code.
func test(function:String -> String) -> String
{
return function("test")
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle)
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" })
println(resultFunc)
println(resultBlock)
println(resultAnon)
Swift, optimized for closures
As Swift is optimized for asynchronous development, Apple worked more on closures.
The first is that function signature can be inferred so you don't have to rewrite it.
Access params by numbers
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
Params inference with naming
let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })
Trailing Closure
This special case works only if the block is the last argument, it's called trailing closure
Here is an example (merged with inferred signature to show Swift power)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
Finally:
Using all this power what I'd do is mixing trailing closure and type inference (with naming for readability)
PFFacebookUtils.logInWithPermissions(permissions) {
user, error in
if (!user) {
println("Uh oh. The user cancelled the Facebook login.")
} else if (user.isNew) {
println("User signed up and logged in through Facebook!")
} else {
println("User logged in through Facebook!")
}
}
Hello, Swift
Complementing what #Francescu answered.
Adding extra parameters:
func test(function:String -> String, param1:String, param2:String) -> String
{
return function("test"+param1 + param2)
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle, "parameter 1", "parameter 2")
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle, "parameter 1", "parameter 2")
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" }, "parameter 1", "parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
You can follow the format below and can use the testingObjectiveCBlock property in the class.
typedef void (^testingObjectiveCBlock)(NSString *errorMsg);
#interface MyClass : NSObject
#property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
#end
For more info have a look here