How can I get a list of functions a protocol defines? - objective-c

I know there is protocol_copyMethodDescriptionList defined in the Objective-C Runtime, but I don't want to have to go so deep, or work with c-arrays. Are there any methods for the Protocol object that can do this? Where can I find any documentation for the Protocol object? I'm hoping for something like:
[foo getMethodsThisProtocolDefines];
where foo is a Protocol.

The Protocol class has been deprecated since Leopard/ObjC 2.0.* Thus, there are no methods on it, nor any current documentation. The only way to interact with a protocol is via the runtime functions.
The structures contained in the protocol's method list aren't objects, either, so they couldn't go into an NSArray without being wrapped anyways.
It's not particularly arduous to deal with the array that's returned from protocol_copyMethodDescriptionList(); you just have to remember to free() it. If you have a particular selector in mind, you can also check the protocol using protocol_getMethodDescription(), which doesn't require any memory management on your part. For example:
BOOL method_description_isNULL(struct objc_method_description desc)
{
return (desc.types == NULL) && (desc.name == NULL);
}
const char * procure_encoding_string_for_selector_from_protocol(SEL sel, Protocol * protocol)
{
static BOOL isReqVals[4] = {NO, NO, YES, YES};
static BOOL isInstanceVals[4] = {NO, YES, NO, YES};
struct objc_method_description desc = {NULL, NULL};
for( int i = 0; i < 4; i++ ){
desc = protocol_getMethodDescription(protocol,
sel,
isReqVals[i],
isInstanceVals[i]);
if( !method_description_isNULL(desc) ){
break;
}
}
return desc.types;
}
*In fact, it seems (based on a note in the runtime reference) that the name is now just an alias for Class.

You probably want this. Objective-C wrapper for the Objective-C runtime.

Check protocol_copyMethodDescriptionList from Objective-C runtime. This would return back an array of methods on the protocol.

Related

Lazy loading Objective-C class with int properties

I use the following as a getter for a property in one of my classes:
- (NSString *)version
{
if (_version == nil) {
_version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
}
return _version;
}
This works well. However, when I try the same for an int property I obviously get an error since int are never nil. What is the best way around this?
- (int)numberOfDays
{
if (_numberOfDays == nil) {
// relatively memory intense calculation that works out numberOfDays:
_numberOfDays = X;
}
return _numberOfDays;
}
Firstly, using int is not recommended Objective-C if possible. If you need to use a primitive integer type, you should use NSInteger. The size of NSInteger is determined at compile time based on the architecture(s) being built for. int is a static size that will not widen for different architectures. It's OK to use it, just be aware.
Using NSInteger, you still face the same problem, it can't be nil. You should therefore make your property an NSNumber which you can init with the result of your computation with [NSNumber numberWithInteger:anInteger];. That way, you can keep you nil check on your property and only do the computation once to create your NSNumber.
Add another boolean instance variable _numberOfDaysCalculated.
A thread-safe version would be
- (int)numberOfDays
{
#synchronized(self) {
if (!_numberOfDaysCalculated) {
// relatively memory intense calculation that works out numberOfDays:
_numberOfDays = X;
_numberOfDaysCalculated = YES;
}
}
return _numberOfDays;
}
Alternatively, if there is some "invalid" value of the property, you can use that
as a "not yet computed" marker. For example, if the computed value of numberOfDays has to be non-negative, you could initialize _numberOfDays = -1 in the init method,
and then test for if (_numberOfDays == -1) in the lazy getter method.
Use GCD.
static dispatch_once_t tok;
dispatch_once(&tok, ^{ memory_intensive_computation(); });
No, don't use GCD, I missed the point. In an instance method, you want to tie information to each instance, so using a static dispatch token is not appropriate. Maybe you should just stick with the "boolean flag as instance variable" approach.
Alternatively, you can initialize the int to a value which is known to be out of its valid range (for example, I suppose that numberOfDays can never be negative) and use that as a condition for performing the calculation.
Use a NSNumber to store the int value.
- (int)numberOfDays
{
if (_numberOfDays == nil) {
// relatively memory intense calculation that works out numberOfDays:
_numberOfDays = #(X);
}
return [_numberOfDays intValue];
}
I would initialize the _numberOfDays in the -init with NSNotFound and test for that in the getter.

Why does "conformsToProtocol" not check for "required" method implementations?

I am trying to enforce a "formal" #protocol, but cannot reliably test my classes/instances as to whether they ACTUALLY implement the protocol's "required" methods, vs. simply "declaring" that they conform to the protocol.
A complete example of my quandary…
#import <Foundation/Foundation.h>
#protocol RequiredProtocol
#required
- (NSString*) mustImplement; #end
#interface Cog : NSObject <RequiredProtocol> #end
#implementation Cog #end
#interface Sprocket : NSObject #end
#implementation Sprocket
- (NSString*) mustImplement
{ return #"I conform, but ObjC doesn't care!"; } #end
int main(int argc, char *argv[]) {
Protocol *required = #protocol(RequiredProtocol);
SEL requiredSEL = #selector(mustImplement);
void (^testProtocolConformance)(NSObject*) = ^(NSObject *x){
NSLog(#"Protocol:%#\n"
"Does %# class conform:%# \n"
"Do instances conform:%# \n"
"Required method's result:\"%#\"",
NSStringFromProtocol ( required ),
NSStringFromClass ( x.class ),
[x.class conformsToProtocol:required] ? #"YES" : #"NO",
[x conformsToProtocol:required] ? #"YES" : #"NO",
[x respondsToSelector:requiredSEL] ? [x mustImplement]
: nil );
};
testProtocolConformance ( Cog.new );
testProtocolConformance ( Sprocket.new );
}
Result:
Protocol:RequiredProtocol
Does Cog class conform:YES
Do instances conform:YES
Required method's result:"(null)"
Protocol:RequiredProtocol
Does Sprocket class conform:NO
Do instances conform:NO
Required method's result:"I conform, but ObjC doesn't care!"
Why is it that a class and it's instances that DO implement the #protocol's methods (Sprocket) return NO to conformsToProtocol?
And why does one that DOESN'T ACTUALLY conform, but SAYS that it DOES (Cog) return YES?
What is the point of a formal protocol if the declaration is all that's needed to feign conformance?
How can you ACTUALLY check for complete implementation of multiple #selectors without MULTIPLE calls to respondsToSelector?
#Josh Caswell.. Without diffing the two.. I'd guess that your response achieves similar effect to the category on NSObject I've been using in the meantime…
#implementation NSObject (ProtocolConformance)
- (BOOL) implementsProtocol:(id)nameOrProtocol {
Protocol *p = [nameOrProtocol isKindOfClass:NSString.class]
? NSProtocolFromString(nameOrProtocol)
: nameOrProtocol; // Arg is string OR protocol
Class klass = self.class;
unsigned int outCount = 0;
struct objc_method_description *methods = NULL;
methods = protocol_copyMethodDescriptionList( p, YES, YES, &outCount);
for (unsigned int i = 0; i < outCount; ++i) {
SEL selector = methods[i].name;
if (![klass instancesRespondToSelector: selector]) {
if (methods) free(methods); methods = NULL; return NO;
}
}
if (methods) free(methods); methods = NULL; return YES;
}
#end
Conforming to a protocol is just a "promise", you can't know if the receiver of conformsToProtocol: actually implements all the required methods. Is enough that you declare that the class conforms to the protocol using the angle brackets syntax, and conformsToProtocol: will return yes:
Discussion
A class is said to “conform to” a protocol if it adopts the protocol or inherits from another class that adopts it. Protocols are adopted by listing them within angle brackets after the interface declaration.
Full source: NSObject's conformsToProtocol: .
Protocols declarations have just the advantage that you can know at compile time if a class really adopts that required methods. If not, a warning will be given. I suggest to don't rely on conformsToProtocol:, but to use introspection instead. That is, verify if a class/object implements a method by calling instancesRespondToSelector: / respondsToSelector: :
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
- (BOOL)respondsToSelector:(SEL)aSelector;
What compiler are you using? Xcode/Clang issues 2 warnings and 1 error...
Think of a protocol as a club with membership requirements. Asking whether someone is a member of the club, provable by them having a membership card (NSObject<ReqiredProtocol>), should tell you that a person meets those requirements. However the lack of a membership doesn't mean they don't meet the requirements.
E.g. someone (Sprocket) might meet all the requirements to join but choose not to. Someone else (Cog) may failed to meet the requirements but a sloppy administrator might let them in.
The latter is why I asked about the compiler (the sloppy administrator ;-)). Try your code as entered on Xcode 4.6.3/Clang 4.2 produces warnings and errors (as does using GCC 4.2):
The warnings state that Cog fails to implement the required methods;
The error complains about [x mustImplement] as x is not known to have the required method as it is of type NSObject - you need to cast to remove that, just [(id)x mustImplement] will do as you've already tested the method exists.
In summary, you can only rely on conformsToProtocol if you know the originator of the code didn't ignore compiler warnings - the checking is done at compile time.
Addendum
I missed the last sentence of your question. If you wish to discover whether a class meets the requirements of a protocol, even if it doesn't declare that it does, e.g. Sprocket above (or if you are obtaining code from folk who ignore compiler warnings - the Cog author above), then you can do so using the facilities of the Obj-C runtime. And you'll only have to write one call to repsondsToSelector...
I just typed in the following and quickly tested it on your sample. It is not throughly tested by any means, caveat emptor etc. Code assumes ARC.
#import <objc/runtime.h>
#interface ProtocolChecker : NSObject
+ (BOOL) doesClass:(Class)aClass meetTheRequirementsOf:(Protocol *)aProtocol;
#end
#implementation ProtocolChecker
+ (BOOL) doesClass:(Class)aClass meetTheRequirementsOf:(Protocol *)aProtocol
{
struct objc_method_description *methods;
unsigned int count;
// required instance methods
methods = protocol_copyMethodDescriptionList(aProtocol, YES, YES, &count);
for (unsigned int ix = 0; ix < count; ix++)
{
if (![aClass instancesRespondToSelector:methods[ix].name])
{
free(methods);
return NO;
}
}
free(methods);
// required class methods
methods = protocol_copyMethodDescriptionList(aProtocol, YES, NO, &count);
for (unsigned int ix = 0; ix < count; ix++)
{
if (![aClass respondsToSelector:methods[ix].name])
{
free(methods);
return NO;
}
}
free(methods);
// other protocols
Protocol * __unsafe_unretained *protocols = protocol_copyProtocolList(aProtocol, &count);
for (unsigned int ix = 0; ix < count; ix++)
{
if (![self doesClass:aClass meetTheRequirementsOf:protocols[ix]])
{
free(protocols);
return NO;
}
}
free(protocols);
return YES;
}
#end
You should of course want to know exactly how this works, especially the * __unsafe_unretained * bit. That is left as an exercise :-)
CRD is right; the compiler tells you about actual conformance, and it should be listened to. If that's being ignored, the runtime doesn't have any built-in method to double-check. Classes maintain internal lists of protocol objects internally; conformsToProtocol: just looks at that.
At the risk that someone is going to come along and tell me to stop fiddling with the ##(%!^& runtime again, if you really truly need to check actual implementation, this is one way you can do so:
#import <objc/runtime.h>
BOOL classReallyTrulyDoesImplementAllTheRequiredMethodsOfThisProtocol(Class cls, Protocol * prtcl)
{
unsigned int meth_count;
struct objc_method_description * meth_list;
meth_list = protocol_copyMethodDescriptionList(p,
YES /*isRequired*/,
YES /*isInstanceMethod*/,
&meth_count);
/* Check instance methods */
for(int i = 0; i < meth_count; i++ ){
SEL methName = meth_list[i].name;
if( ![class instancesRespondToSelector:methName] ){
/* Missing _any_ required methods means failure */
free(meth_list);
return NO;
}
}
free(meth_list);
meth_list = protocol_copyMethodDescriptionList(p,
YES /*isRequired*/,
NO /*isInstanceMethod*/,
&meth_count);
/* Check class methods, if any */
for(int i = 0; i < meth_count; i++ ){
SEL methName = meth_list[i].name;
if( ![class respondsToSelector:methName] ){
free(meth_list);
return NO;
}
}
free(meth_list);
return YES;
}
If I had a hammer...
All of these answers are good. To them, I would add one more point: calling conformsToProtocol: is almost always a mistake. Because it tells whether the class says that it conforms to the protocol, rather than whether it actually provides specific methods:
It is possible to create a class that claims to conform, but does not, by silencing various warnings, resulting in crashes if you assume that a required method exists.
It is possible to create a class that conforms to the protocol but does not claim to do so, resulting in methods not getting called on a delegate even though they exist.
It can lead to programming errors creeping in when the protocol changes, because your code checks for conformance to a protocol before calling a method that used to be required, but no longer is.
All of these issues can cause unexpected behavior.
IMO, if you want to know if a class handles a method, the safest approach is to explicitly ask it if it handles that method (respondsToSelector:), rather than asking it if it conforms to a protocol that just happens to contain that method.
IMO, conformsToProtocol: should really have been a function in the Objective-C runtime instead of being exposed on NSObject, because it generally causes more problems than it solves.

Is it okay to return a subclass from a class constructor that uses instancetype?

I have a class method in a category to construct a Cocoa collection in some way that the built-in initializers don't allow. Due to the limited initializer functionality, I have to use the mutable version of the collection to actually build it. Here's an example for NS{Mutable}IndexSet:
#implementation NSIndexSet (WSSNonContiguous)
+ (instancetype)WSSIndexSetFromMask:(NSUInteger)mask
{
NSMutableIndexSet * set = [NSMutableIndexSet indexSet];
for( NSUInteger i = 0; i < (sizeof(NSUInteger) * 8); i++ ){
if( mask & (1l << i) ){
[set addIndex:i];
}
}
return set;
}
My return type is sometimes a lie here -- there's always a mutable collection being returned, whether the user is requesting an immutable version or not.
Is it still appropriate to use instancetype in cases like this, or should I go with id? If I do use instancetype, should I also be explicitly re-creating the collection:
// Ick?
return [[self alloc] initWithIndexSet:set];
to make sure an immutable copy is returned when the call is +[NSIndexSet WSSIndexSetFromMask:]?
Everything is okay:
NSIndexSet *set = [[NSIndexSet WSSIndexSetFromMask:0] addIndex:0];
No visible #interface for 'NSIndexSet' declares the selector 'addIndex:'
instancetype says to the sender, that you return a instance of the receivers type even it is a subtype. For the sender it is a NSIndexSet, because it is send to the class object of NSIndexSet.
An introspection that way, that someone looks to the return type and sees a subclass and takes any advantage out of this information, is malformed. The contract is build with the return type and this is in this case NSIndexSet.

When I have use ARC in IOS project,how can I use void *?

LooK this method:
beginAnimations:context:
This is a method of class UIView. The context need parameter which is a type of void-pointer,and I need to send a UIImageView to context.
I get a warning,which says void* has been forbidden when I use ARC. So how can I send UIImageView to context except not use ARC.
The comments above provided the correct answer for this particular case (use the block-based animation methods) but in general if you have an API which takes a context void * and you'd like to pass an object, I find it best to convert your id to a CFTypeRef so you can get manual memory management semantics on the pointer (CFTypeRef is a typedef for void *), etc. Note however that this requires that the callback must be called in order to get your object released (i.e. converted back to ARC's built-in management).
Here's an example for some imaginary API I just dreamt up:
- (void) doSomethingWithObject: (id) object {
// use CFBridgingRetain() to turn object into a manually-retained CFTypeRef/void*
[someObject performBackgroundTaskWithTarget: self
selector: #selector(bgTask:)
context: CFBridgingRetain(object)];
}
- (void) bgTask: (void *) context
{
// use CFBridgingRelease() to turn our void*/CFTypeRef into an ARC-managed id
id object = CFBridgingRelease((CFTypeRef)context);
...
}

Implementing NSFastEnumerator: EXC_BAD_ACCESS when iterating with for…in

I have a data structure that I wanted to enumerate. I tried to implement my object's NSFastEnumerator as follows:
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(__unsafe_unretained id [])buffer
count:(NSUInteger)len {
NSUInteger c = 0;
while (c < len) {
id obj = [self objectAtIndex:state->state];
if (obj == nil) break;
buffer[c] = obj;
c++;
state->state++;
}
state->itemsPtr = buffer;
state->mutationsPtr = nil;
return c;
}
If I use objectAtIndex directly, my object works properly. I get a nil when the index doesn't exist. But when I then use the for loop:
for (Pin *pin in coll) { ... }
the code runs through the above function fine and fills in state with what appears to be valid values and returns the number of objects, then I get an EXC_BAD_ACCESS failure at the for statement itself.
What am I doing wrong in this implementation?
I just had a similar issues, and after looking more closely into Apple's FastEnumerationSample, this part (that I had overlooked) jumped at me:
// We are not tracking mutations, so we'll set state->mutationsPtr to point into one of our extra values,
// since these values are not otherwise used by the protocol.
// If your class was mutable, you may choose to use an internal variable that is updated when the class is mutated.
// state->mutationsPtr MUST NOT be NULL.
state->mutationsPtr = &state->extra[0];
The important part being: state->mutationsPtr MUST NOT be NULL. I just used the example line provided and it worked like a charm!
I'm assuming you're using ARC. The problem may be that the buffer is an array of __unsafe_unretained objects, so ARC might be over-releasing them. But what does your objectAtIndex: method look like? This shouldn't be a problem if you are returning objects that are guaranteed to be alive at least as long as your object itself.
Instead of:
id obj = [self objectAtIndex:state->state];
use
__unsafe_unretained id = [self objectAtIndex:state->state];