I was looking through one of Apple's XCode tutorials and came across something that looked like this inside the implementation of a class method:
void (^foo)(void);
foo = ^(void) {
NSLog(#"Hello, World!");
};
foo();
Now obviously this is some kind of function declaration, implementation, and usage. However, I'd like to know more about it, what it is called, and what its limitations and advantages are. My searches online are turning up nothing relevant. Can anyone point me in the proper direction?
They're called blocks. You can think of a block as a chunk of code that you can pass around to other parts of your program. They were added by Apple to its C and Objective-C compilers relatively recently, but some newer APIs take blocks instead or in addition to selectors or function pointers.
Blocks and block variables.
Here's some reading:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html
http://pragmaticstudio.com/blog/2010/7/28/ios4-blocks-1
http://thirdcog.eu/pwcblocks/
Related
(I'm a cocoa beginner and ) I'm wondering why we should do:
NSLog(#"this is the variable value: %d",variable);
and not something like this:
[NSLog outputThis:#"this is the variable value: %d" param:variable];
I agree this is pretty confusing when you're starting out. The main reason is that the NSLog method, like many others in Core Foundation, is a C-based API, rather than an Objective-C API. C-style functions look like this myFunction(myParameter1, myParameter2).
All the GUI stuff you're probably used to [UIView presentModalViewController:] etc is based around an Objective-C API, with the square brackets that you've seen for functions (called selectors in Obj-C) . The Objective-C language sits on top of C, so you will find both styles in most apps.
NSLog may seem like a class, but it isn't.
NSLog is a FoundationKit function for printing debug statements to the
console. It is defined in NSObjCRuntime.h:
void NSLog(NSString format, ...);
There is a good amount of information here: http://cocoadev.com/wiki/NSLog
EDIT: As #fyngyrz pointed out, the page is dead. So here is a wayback-machine version of the page from 2012
As I understand it, NSLog isn't an Objective C function but a C function built into the foundation of Cocoa. Therefore it conforms to basic C functions with variadic arguments.
As you may be aware, blocks take -invoke:
void(^foo)() = ^{
NSLog(#"Do stuff");
};
[foo invoke]; // Logs 'Do stuff'
I would like to do the following:
void(^bar)(int) = ^(int k) {
NSLog(#"%d", k);
};
[bar invokeWithParameters:7]; // Want it to log '7', but no such instance method
The ordinary argument-less -invoke works on bar, but it prints a nonsense value.
I can't find a direct message of this kind I can send to a block, nor can I find the original documentation that would describe how blocks take -invoke.
Is there a list of messages accepted by blocks?
(Yes, I have tried to use class_copyMethodList to extract a list of methods from the runtime; there appear to be none.)
Edit: Yes, I'm also aware of invoking the block the usual way (bar(7);). What I'm really after is a selector for a method I can feed into library code that doesn't take blocks (per-se).
You can invoke it like a function:
bar(7);
There's even an example in the documentation that uses exactly the same signature. See Declaring and Using a Block.
The best reference on the behavior of blocks is the Block Language Specification(RTF) document. This mentions certain methods that are supported (copy, retain, etc.) but nothing about an -invoke method.
A blocks very definition is the sum total of "messages" that the block can receive, in terms of the calling parameters/ABI.
This is for a couple of reasons:
First, a block is not a function and a block pointer is not a function pointer. They cannot be used interchangeably.
Secondly, the C ABI is such that you have to have a declaration of the function begin called when the call site is being compiled if the parameters are to be encoded correctly.
The alternative is to use something like NSInvocation, which allows the arguments to be encoded individually, but even that still requires full C ABI knowledge for each individual argument.
Ultimately, if you can compile a call site that has all the parameters, be it an Objective-C method or a function call, to the fidelity necessary to make the compiler happy, you can convert that call site into a call to the block.
I.e. unless you clarify your question a bit, what you are asking for is either already supported or nigh impossible due to the vagaries of the C ABI.
What is the difference between the two? If I'm writing a program, when would I need a this:
void aFunction() {
//do something
}
and when would I need this:
-(void)aMethod {
//do something else
}
Actually, an Objective-C method is just a C function with two arguments always present at the beginning.
This:
-(void)aMethod;
Is exactly equivalent to this:
void function(id self, SEL _cmd);
Objective-C's messaging is such that this:
[someObject aMethod];
Is exactly equivalent to this (almost -- there is a variadic argument ABI issue beyond the scope of this answer):
objc_msgSend(someObject, #selector(aMethod));
objc_msgSend() finds the appropriate implementation of the method (by looking it up on someObject) and then, through the magic of a tail call optimization, jumps to the implementation of the method which, for all intents and purposes, works exactly like a C function call that looks like this:
function(someObject, #selector(aMethod));
Quite literally, Objective-C was originally implemented as nothing but a C preprocessor. Anything you can do in Objective-C could be rewritten as straight C.
Doing so, however, would be a complete pain in the ass and not worth your time beyond the incredibly educational experience of doing so.
In general, you use Objective-C methods when talking to objects and function when working with straight C goop. Given that pretty much all of Mac OS X and iOS provide Objective-C APIs -- certainly entirely so for the UI level programming entry points -- then you use Obj-C most of the time.
Even when writing your own model level code that is relatively standalone, you'll typically use Objective-C simply because it provides a very natural glue between state/data & functionality, a fundamental tenant of object oriented programming.
In Objective-C each function operates on an object, like
[myObject myFunction]
A C method has the form:
return-type function-name(argument1, argument2, etc) {}
An Objective-C instance method has the form:
-(return-type)function-name:argument1 {}
or for a multi-argument function
-(return-type)function-name:argument1 function-name:argument2 {}
I always use Objective-C-style methods in Obj-C programming, even though you can still use C-type functions as well.
I suppose the equivalent in C to [myObject myMethod:arg] might be myObject.myMethod(arg)
The first is a freestanding function. The second is an instance method for an Objective-C class. So I guess you would need the second version if you're actually writing a class.
Not knowing Obj-C I could use some help to traslate this one line of code:
[[TVOutManager sharedInstance] startTVOut];
into a C# version I can use in MonoTouch.
I've managed to get the XCode project compiled to a static library, now I'm trying to figure out how to turn it on... The orginal project is posted here: http://www.touchcentric.com/blog/
TIA,
Rick
[obj myMsg] is Objective-C syntax for sending the myMsg message to the obj instance. It is, at first blush, a lot like obj.myMsg() in C#. Objective-C uses message passing rather than function calls, however, so the two are actually very different semantically. You can often gloss over the differences, but if you are going to do any significant work on OS X or iOS, it's worth reading the Objective-C language guide carefully. I'm not a MonoTouch/MonoMac expert, but I believe that the answer to your specific question is:
TVOutManager.sharedInstance.startTVOut();
assuming sharedInstance is mapped as a static property of type TVOutManager, or
TVOutManager.sharedInstance().startTVOut();
if sharedInstance is mapped as a class method in Objective-C.
I am trying to learn how to write plugins using SIMBL. I got my plugin to load with the target application, and also know the method that I wish to override. However, I am not able to use class_getInstanceMethod correctly based on snippets on the Internet. Have things changed in OSX 10.6 and/or ObjC2?
The following code from culater.net gives "Dereferencing pointer to incomplete type" on the second-last statement:
BOOL DTRenameSelector(Class _class, SEL _oldSelector, SEL _newSelector)
{
Method method = nil;
// First, look for the methods
method = class_getInstanceMethod(_class, _oldSelector);
if (method == nil)
return NO;
method->method_name = _newSelector;
return YES;
}
Is there a complete example of how to override a method using SIMBL plugins? Thanks!
The Obj-C runtime has changed in Objective-C 2, the code you quoted uses the older one.
(Well, on 32 bit apps, it's more correct to say there're two interfaces to the same runtime, depending on how you compile your binary; both work in the end. But it's easier to think that things changed in Objective-C 2. And you should use the newer APIs because it's easier to use, and it works both in 32 bit and 64 bit.)
New references are the Guide and the Reference. The basic change is that the internal struct is no longer public, is opaque. So you can't access its member directly. Instead, you need to use an API.
Typically things are easier in the new runtime. To replace an IMP, one just uses
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types);
To get the type encoding, use
const char * method_getTypeEncoding(Method method);
against the original method you're replacing. In practice, that would be
method_getTypeEncoding(class_getInstanceMethod([SomeClass class], #selector(someSelector:you:want:to:replace:)));
To learn more about the runtime, I heartily recommend the wonderful series of blog posts Friday Q&A by Mike Ash.
Have fun and good luck!
If you're looking to swizzle a method, you might consider using the method_exchangeImplementations function instead.