Supposed I have two objective-c classes, LBFoo and LBBar.
In LBFoo I have a method that looks like this:
- (void)doSomethingWithFoo:(NSNumber*)anArgument
{
if(anArgument.intValue > 2)
[LBBar doSomethingWithLBBar];
else
[LBBar doSomethingElseWithLBBar];
}
What I would like to do instead is pass an implementation to LBBar that was not declared ahead of time. (As in dynamically override an existing #selector within LBBar)
I know that an IMP type exists, is it possible to pass an IMP to a class in order to change its selector implementation.
you can use the method_setImplementation(Method method, IMP imp) function in objective-c runtime.
if you want to set an instance method, it would work something like this
method_setImplementation(class_getInstanceMethod([yourClass class], #selector(yourMethod)), yourIMP);
if you want a class method, just use class_getClassMethod instead of class_getInstanceMethod. The arguments should be the same.
that's all there is to it. Note that IMP is just a void function pointer with the first 2 parameters being id self and SEL _cmd
You can certainly use the runtime functions to do something like this,* but I'd suggest that this is exactly the sort of problem that Blocks were introduced to solve. They allow you to pass around a chunk of executable code -- your method can actually accept a Block as an argument and run it.
Here's a SSCCE:
#import <Foundation/Foundation.h>
typedef dispatch_block_t GenericBlock;
#interface Albatross : NSObject
- (void)slapFace:(NSNumber *)n usingFish:(GenericBlock)block;
#end
#implementation Albatross
- (void)slapFace:(NSNumber *)n usingFish:(GenericBlock)block
{
if( [n intValue] > 2 ){
NSLog(#"Cabbage crates coming over the briny!");
}
else {
block(); // Execute the block
}
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
Albatross * p = [Albatross new];
[p slapFace:[NSNumber numberWithInt:3] usingFish:^{
NSLog(#"We'd like to see the dog kennels, please.");
}];
[p slapFace:[NSNumber numberWithInt:1] usingFish:^{
NSLog(#"Lemon curry?");
}];
}
return 0;
}
*Note that using method_setImplementation() will change the code that's used every time that method is called in the future from anywhere -- it's a persistent change.
Related
Let's say that I declare property in following way:
#property(nonatomic, strong, getter = isWorking) BOOL working;
Then instead of having the property to be synthesized I write the getter myself (and add some custom logic to it).
What will happen if I access the property in following way:
BOOL work = self.working;
Is the getter (and my custom logic there) still called or is it called only when I access the property using getter explicitly (BOOL work = self.isWorking;) ?
Oops. Just tried it. Apparently i use dot notation too much, and didn't realize just how much it was doing. :P
#import "NSObject.h"
#include <stdio.h>
#interface Test : NSObject
#property (getter=myStuff) int stuff;
#end
#implementation Test
-(int)myStuff { return 42; }
-(void)setStuff:(int)value { /* don't care */ }
#end
int main() {
#autoreleasepool {
Test* test = [[Test alloc] init];
/* All these work... */
printf("test.stuff == %d\n", test.stuff);
printf("[test myStuff] == %d\n", [test myStuff]);
printf("test.myStuff == %d\n", test.myStuff);
/* but here, there's an exception */
printf("[test stuff] == %d\n", [test stuff]);
return 0;
}
}
When i compile this (using clang in Linux), there are two warnings about the oddness of a missing -(int)stuff. And the output looks like
chao#chao-VirtualBox:~/code/objc$ ./a.out
test.stuff == 42
[test myStuff] == 42
test.myStuff == 42
: Uncaught exception NSInvalidArgumentException, reason: -[Test stuff]: unrecognized selector sent to instance 0x2367f38
chao#chao-VirtualBox:~/code/objc$
So, umm, yeah. Disregard half of the stuff below. :P
self.working is just syntactic sugar for [self working] (or [self setWorking:value] if you're assigning to it). Either one will do the same thing: return the value of [self isWorking], because that's the getter you defined.
If you want to avoid the getter, try _working or self->_working (or whatever you named the ivar). Otherwise, self.working, [self working], and [self isWorking] (and even self.isWorking if you're feeling brave) should all give you the same result.
I have been looking around online, doing research into how to use blocks. I have also decided to set up a basic example to try and understand the way in which they work.
Essentially what I want to do is have a 'block variable' (no sure if thats the correct term) in which I can store a block of code. I then want to be able to set the code in this block at pointX (methodA or methodB) in my code, then run the block of code at pointY (methodX).
So to be specific, my question is 3-fold
Using the example below is the setup / usage of blocks correct and valid?
In methodX how do I execute the code inside the block (self.completionBlock)?
When creating the block in methodA and methodB will the code be called there and then? If so how can I stop this from happening (all I want to do is set up the code in the block to be called later)?
I may have completely misunderstood how blocks are used, apologies if this is the case, however I'm relatively new to Objective-C and I'm trying to learn.
Here is my code so far:
.h
typedef void (^ CompletionBlock)();
#interface TestClass : NSObject
{
CompletionBlock completionBlock;
NSString *stringOfText;
NSString *otherStringOfText;
}
#property(nonatomic, copy)CompletionBlock completionBlock;
#property(nonatomic, retain)NSString *stringOfText;
#property(nonatomic, retain)NSString *otherStringOfText;
- (void)methodA:(NSString *)myText;
- (void)methodB:(NSString *)myText and:(NSString *)myOtherText;
- (void)methodX;
#end
.m
- (void)methodA:(NSString *)myText;
{
if ([self.stringOfText isEqualToString:#""])
{
// Set the variable to be used by the completion block
self.stringOfText = #"I visited methodA"; // normally make use of myText
// Create the completion block
__block TestClass *blocksafeSelf = self;
self.completionBlock = ^()
{
[blocksafeSelf methodA:blocksafeSelf.stringOfText];
blocksafeSelf.stringOfText = nil;
};
}
else
{
// Do some other stuff with self.stringOfText
}
}
- (void)methodB:(NSString *)myText and:(NSString *)myOtherText;
{
if ([self.stringOfText isEqualToString:#""] || [self.otherStringOfText isEqualToString:#""])
{
// Set the variable to be used by the completion block
self.stringOfText = #"I visited methodB"; // normally make use of myText
self.otherStringOfText = #"I also visited methodB"; // normally make use of myOtherText
// Create the completion block
__block TestClass *blocksafeSelf = self;
self.completionBlock = ^()
{
[blocksafeSelf methodB:blocksafeSelf.stringOfText and:blocksafeSelf.otherStringOfText];
blocksafeSelf.stringOfText = nil;
blocksafeSelf.otherStringOfText = nil;
};
}
else
{
// Do some other stuff with self.stringOfText and self.otherStringOfText
}
}
- (void)methodX
{
// At this point run the block of code in self.completionBlock...how?!
}
In my example either methodA or methodB will be called first. Then some time later (perhaps from a different class) methodX will be called (only ever after methodA or methodB have been called).
It's worth noting that the methods methodA, methodB and methodX are all in a singleton class.
NOTE: This is just a dummy example to try and understand the workings of blocks, I'm fully aware there are other ways to achieve the same result.
Here's the code, just to be clear:
- (void)methodX
{
if(self.completionBlock)
self.completionBlock();
}
I think you want to do self.completionBlock(); in methodX.
How can I pass a Block to a Function/Method?
I tried - (void)someFunc:(__Block)someBlock with no avail.
ie. What is the type for a Block?
The type of a block varies depending on its arguments and its return type. In the general case, block types are declared the same way function pointer types are, but replacing the * with a ^. One way to pass a block to a method is as follows:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
But as you can see, that's messy. You can instead use a typedef to make block types cleaner:
typedef void (^ IteratorBlock)(id, int);
And then pass that block to a method like so:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
The easiest explanation for this question is follow these templates:
1. Block as a method parameter
Template
- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
// your code
}
Example
-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
// your code
}
Other use of cases:
2. Block as a Property
Template
#property (nonatomic, copy) returnType (^blockName)(parameters);
Example
#property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);
3. Block as a method argument
Template
[anObject aMethodWithBlock: ^returnType (parameters) {
// your code
}];
Example
[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
// your code
}];
4. Block as a local variable
Template
returnType (^blockName)(parameters) = ^returnType(parameters) {
// your code
};
Example
void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
// your code
};
5. Block as a typedef
Template
typedef returnType (^typeName)(parameters);
typeName blockName = ^(parameters) {
// your code
}
Example
typedef void(^completionBlock)(NSArray *array, NSError *error);
completionBlock didComplete = ^(NSArray *array, NSError *error){
// your code
};
This might be helpful:
- (void)someFunc:(void(^)(void))someBlock;
You can do like this, passing block as a block parameter:
//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
NSLog(#"bbb");
};
//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
NSLog(#"aaa");
completion();
};
//invoking block "block" with block "completion" as argument
block(completion);
One more way to pass block using с functions in example below.
I`ve created functions to perform anything in background and on main queue.
blocks.h file
void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));
blocks.m file
#import "blocks.h"
void performInBackground(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}
void performOnMainQueue(void(^block)(void)) {
if (nil == block) {
return;
}
dispatch_async(dispatch_get_main_queue(), block);
}
Than import blocks.h when necessary and invoke it:
- (void)loadInBackground {
performInBackground(^{
NSLog(#"Loading something in background");
//loading code
performOnMainQueue(^{
//completion hadler code on main queue
});
});
}
You also can set block as a simple property if it's applicable for you:
#property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);
make sure that block property is "copy"!
and of course you can also use typedef:
typedef void (^SimpleBlock)(id);
#property (nonatomic, copy) SimpleBlock someActionHandler;
Also you invoke or call a block in using usual c function syntax
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
More info on blocks here
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxGettingStarted.html#//apple_ref/doc/uid/TP40007502-CH7-SW1
I always tend to forget about blocks syntax. This always comes to my mind when I need to declare a block. I hope it helps someone :)
http://fuckingblocksyntax.com
I wrote a completionBlock for a class which will return the values of dice after they have been shaken:
Define typedef with returnType (.h above #interface declaration)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Define a #property for the block (.h)
#property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
Define a method with finishBlock (.h)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Insert previous defined method in .m file and commit finishBlock to #property defined before
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
To trigger completionBlock pass predefined variableType to it
(Don't forget to check whether the completionBlock exists)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
Despite the answers given on this thread, I really struggled to write a function which would take a Block as a function - and with a parameter. Eventually, here's the solution I came up with.
I wanted to write a generic function, loadJSONthread, which would take the URL of a JSON Web Service, load some JSON data from this URL on a background thread, then return an NSArray* of results back to the calling function.
Basically, I wanted to keep all the background-thread complexity hidden away in a generic reuseable function.
Here's how I would call this function:
NSString* WebServiceURL = #"http://www.inorthwind.com/Service1.svc/getAllCustomers";
[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) {
// Finished loading the JSON data
NSLog(#"Loaded %lu rows.", (unsigned long)results.count);
// Iterate through our array of Company records, and create/update the records in our SQLite database
for (NSDictionary *oneCompany in results)
{
// Do something with this Company record (eg store it in our SQLite database)
}
} ];
...and this is the bit I struggled with: how to declare it, and how to get it to call the Block function once the data was loaded, and pass the Block an NSArray* of records loaded:
+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData
{
__block NSArray* results = nil;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// Call an external function to load the JSON data
NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString];
results = [dictionary objectForKey:#"Results"];
dispatch_async(dispatch_get_main_queue(), ^{
// This code gets run on the main thread when the JSON has loaded
onLoadedData(results);
});
});
}
This StackOverflow question concerns how to call functions, passing a Block as a parameter, so I've simplified the code above, and not included the loadJSONDataFromURL function.
But, if you are interested, you can find a copy of this JSON loading function on this blog:
http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm
Hope this helps some other XCode developers !
(Don't forget to vote up this question and my answer, if it does !)
The full template looks like
- (void) main {
//Call
[self someMethodWithSuccessBlock:^{[self successMethod];}
withFailureBlock:^(NSError * error) {[self failureMethod:error];}];
}
//Definition
- (void) someMethodWithSuccessBlock:(void (^) (void))successBlock
withFailureBlock:(void (^) (NSError*))failureBlock {
//Execute a block
successBlock();
failureBlock([[NSError alloc]init]);
}
- (void) successMethod {
}
- (void) failureMethod:(NSError*) error {
}
How do I declare and use small helper functions inside my normal methods ?
In on of my objective-c methods I need a function to find an item within a string
-(void) Onlookjson:(id) sender{
NSString * res = [[sender gstring] copy];
persInfoBirth.text = getKeyValue(res, #"Birth");
}
I came up with a normal C type declaration for helper function getKeyvalue like this
NSString * getKeyvalue(NSString * s, NSString * key){
NSString *trm = [[s substringFromIndex:2] substringToIndex:[s length]-3];
NSArray *list = [trm componentsSeparatedByString:#";"];
//....
NSString res;
res = [list objectAtIndex:1];
//...
return res;
}
Example input string in s:
s=#"{ Birth = "1910"; Death = "1936"; }";
Anyway I get an exception "unrecognized selector sent to instance" for any of the two first lines in the helper function
How do I declare helper functions that are just to be used internally and how to call them safely ?
regards
Martin
Is this the real code? Do you get zero errors and warnings from the compiler? You must not ignore compiler warnings and you should turn on the Static Analyser in addition to the standard warnings.
There are many things wrong with the above code, most of which are nothing todo with declaring and calling methods. There is no way the above code could compile so maybe it pasted incorrectly or something..
Anyway.. declaring and using methods. Why are using a c function? Unless you have a good reason why not use Objective-c ? If you do have a good reason to use a C function the your definition should be:-
NSString *getKeyvalue( NSString *s, NSString *key ){
...
}
note the arguments. As NSString instances reside in the heap (not on the stack) you always want to pass pointers to them.
You then need to put the declaration in the header file:-
NSString *getKeyvalue( NSString *s, NSString *key )
EDIT:
In Objective-c there is no distinction between normal methods and helper methods, there is only one kind, and you have aleray written one
- (void)onLookJson:(id)sender { .. }
Taking it apart..
All methods begin with + or –, indicating Class method or Instance method. As you are familiar with C++ i guess you know what this means.
(void) is the return type. ie this method doesn't return a value. If it did it might look like (float) or (NSString *) or (id).
onLookJson: is the method name and the method takes 1 argument. Notice that the ':' is actually part of the name. This method is never is any circumstance just 'onLookJson'. An argument must always follow the :, so a method that doesn't take any arguments must not have one.
Ex
- (NSString *)fullName { .. }
This is an instance method, for example of a Person Class, you would call it like:-
NSString *theName = [aPerson fullName];
So
a method name that takes no
arguments is like 'speak'
a method
name that takes 1 argument is like
'speakTo:'
a method name that takes 2
arguments is like 'speakTo: language:'
a method name that takes 3
arguments is like 'speakTo: language: volume:'
etc.
All that is left is to put in the argument types and names.
Your function definition:
NSString *getKeyvalue( NSString *s, NSString *key ){
would become..
- (NSString *)getValue:(NSString *)s key:(NSString *)key { .. }
again, you need to declare it in the header or you will get a compiler warning.
- (NSString *)getValue:(NSString *)s key:(NSString *)key;
I want to start a new thread using a C function, not an objective-C method. I tried
[NSThread detachNewThreadSelector: #selector(func) toTarget: nil withObject: id(data)];
where I have
void func(void *data) {
// ...
}
and data is a void *, but I get a runtime crash in objc_msgSend, called from
-[NSThread initWithTarget:selector:object:]
What can I do instead? Is it even possible?
Roll your own:
// In some .h file. #import to make the extension methods 'visible' to your code.
#interface NSThread (FunctionExtension)
+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data;
-(id)initWithFunction:(void (*)(void *))function data:(void *)data;
#end
// In some .m file.
#implementation NSThread (FunctionExtension)
+(void)startBackgroundThreadUsingFunction:(id)object
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
void (*startThreadFunction)(void *) = (void (*)(void *))[[object objectForKey:#"function"] pointerValue];
void *startThreadData = (void *) [[object objectForKey:#"data"] pointerValue];
if(startThreadFunction != NULL) { startThreadFunction(startThreadData); }
[pool release];
pool = NULL;
}
+(void)detachNewThreadByCallingFunction:(void (*)(void *))function data:(void *)data
{
[[[[NSThread alloc] initWithFunction:function data:data] autorelease] start];
}
-(id)initWithFunction:(void (*)(void *))function data:(void *)data
{
return([self initWithTarget:[NSThread class] selector:#selector(startBackgroundThreadUsingFunction:) object:[NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:function], #"function", [NSValue valueWithPointer:data], #"data", NULL]]);
}
#end
NOTE: I wrote the above code and here by place it in the public domain. (sometimes the lawyers like this kind of stuff) It is also completely untested!
You can always remove the NSAutoreleasePool bits if you can guarantee that the thread entry function also creates one... but it's harmless, has no speed penalty what-so-ever, and makes calling arbitrary C functions that much more simpler. I'd say just keep it there.
And you can use it like so:
void bgThreadFunction(void *data)
{
NSLog(#"bgThreadFunction STARTING!! Data: %p", data);
}
-(void)someMethod
{
// init and then start later...
NSThread *bgThread = [[[NSThread alloc] initWithFunction:bgThreadFunction data:(void *)0xdeadbeef] autorelease];
// ... assume other code/stuff here.
[bgThread start];
// Or, use the all in one convenience method.
[NSThread detachNewThreadByCallingFunction:bgThreadFunction data:(void *)0xcafebabe];
}
When run:
2009-08-30 22:21:12.529 test[64146:1303] bgThreadFunction STARTING!! Data: 0xdeadbeef
2009-08-30 22:21:12.529 test[64146:2903] bgThreadFunction STARTING!! Data: 0xcafebabe
Create an Objective-C class with a method that simply calls that function. Take the selector of that method and pass it to NSThread API.
Well, I'm not sure if it's possible, but keep in mind that every Objective-C method has two implicit/hidden arguments, self and _cmd. An IMP is usually typedef'd like this:
typedef id (*IMP)(id,SEL,...);
If you want to jerry-rig methods and selectors, you need to have a method that looks like that:
void func (id self, SEL _cmd, void *firstParameter);
But even after that, you need to register a selector name with the runtime, then you need to associate that selector with the method, but this is done on a class-by-class basis (i.e. classes can have different implementations of the same selector name), so you at least need to have a dummy class.
It is much, much simpler just to create a dummy class and dummy instance of that class than call the various runtime API just to get NSThread to invoke a single C function.
If you don't need NSThread stuff, you can also start a thread with direct POSIX interface.
I want to start a new thread using a C function, not an objective-C method
Then why don't you just use:
POSIX threads,
GCD?
dispatch_async_f() (man) is suited exactly for this purpose.