First of all, I want to be clear that I'm not talking about defining a protocol, and that I understand the concept of
#protocol someprotocol
- (void)method;
#end
I know that the Obj-C runtime allows creation of classes at RUNTIME, as well as its ivars and methods. Also available for creation are SEL-s. I think I'm just missing something, but does anyone know what function to call to create a protocol at runtime? The main reason for this is for conformsToProtocol: to work, so just adding the appropriate methods doesn't really cut it.
Way to add protocol at runtime
Protocol *aProtocol = objc_allocateProtocol("TestingRuntimeDelegate");
AppDelegate *appInstance = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSLog(#"conformed Protocol ..%d",class_conformsToProtocol([self.delegate class], aProtocol));
protocol_addMethodDescription(aProtocol, #selector(itIsTestDelegate), "test", NO, NO);
objc_registerProtocol(aProtocol);
class_addProtocol([appInstance class], aProtocol);
//NSLog(#"adding Protocol %d",class_addProtocol([appInstance class], aProtocol));
if ([self.delegate conformsToProtocol:#protocol(TestDelegate)])
{
NSLog(#"conformed Protocol ..");
}
else
{
NSLog(#"conformed Protocol ..%d",class_conformsToProtocol([appInstance class], aProtocol));
class_conformsToProtocol([self.delegate class], aProtocol);
[appInstance performSelector:#selector(itIsTestDelegate)];
}
But the delegate method must be previously defined on that class otherwise it will crash due to unrecognized selector
or the method can be added at run time..
Then it will work fine..
But the following file must be imported first.
#include <objc/runtime.h>
the following sort of works, but a proper way of doing this would be much appreciated:
Protocol *proto = [Protocol alloc];
object_setInstanceVariable(proto, "protocol_name", &"mySuperDuperProtocol");
void *nada = NULL;
object_setInstanceVariable(proto, "protocol_list", &nada);
object_setInstanceVariable(proto, "class_methods", &nada);
struct objc_method_description_list *methods;
methods = malloc(sizeof(int) + sizeof(struct objc_method_description) * 1);
methods->count = 1;
methods->list[0].name = #selector(foobar:);
methods->list[0].types = "v:#";
object_setInstanceVariable(proto, "instance_methods", &methods);
class_addProtocol([self class], proto);
NSLog(#"%d %s", [self conformsToProtocol:proto], protocol_getName(objc_getProtocol("mySuperDuperProtocol")));
The first NSLog parameter is 1, and isn't when the line adding the protocol to the class is commented out, meaning the protocol is somehow registered with the class. On the other hand, it does not get returned by objc_getProtocol (the second thing logged is nil).
Related
If I have methods like:
- (BOOL)isValidRow:(NSDictionary*)contentVersionRow
do we really have to continually check like this at the beginning of the method
if(![contentVersionRow isKindOfClass:[NSDictionary class]]) {
// Handle unusual situation - probably return NO in this case
}
to really implement proper type-safety inside Objective-C methods? Because in theory the parameter is not guaranteed to point to an NSDictionary object, is this correct?
EDIT: So answers so far seem to indicate we should not check for this, but then what is the difference between checking for this and checking for nil parameter, which I assume we should do? Or should we not check for nil either, if it's not normally expected? Both cases cover the situation of a misbehaving caller.
Just like in C you are dealing with pointers in Objective-C. So saying NSDictionary * simply means "here's a pointer to a memory address that contains an instance of NSDictionary".
Example:
#import <Foundation/Foundation.h>
#interface Test : NSObject
- (void)useDictionary:(NSDictionary *)dictionary;
#end
#implementation Test
- (void)useDictionary:(NSDictionary *)dictionary
{
NSLog(#"Keys: %#", [dictionary allKeys]);
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Test *test = [[Test alloc] init];
// 1: This works fine
[test useDictionary:#{#"key": #"value"}];
// 2: This will cause a compiler warning (or error depending on the options passed to the compiler)
[test useDictionary:#"not a dictionary"];
// 3: This will compile without any warnings
[test useDictionary:(NSDictionary *)#"not a dictionary"];
}
}
The 2nd and 3rd examples will cause the program to crash at runtime. So if you want to pass incorrect things to methods, you can. Usually Xcode will warn you if you have a type-mismatch.
Update about nil-checking: If it's an API-misuse to pass nil to your method, then throw an exception. That's what exceptions are for in Objective-C: to catch programming mistakes, not to handle expected runtime issues (like an unreachable network). If your method can just silently fail if nil is passed in or handle it in a sensible way, then do that instead. For example if you have a method addValue:(NSNumber *)number that adds the given value to a sum then it wouldn't be a big deal if someone called it with nil: Just don't add anything :)
Yes, but you shouldn’t.
Obj-C is a dynamic language, so it is up to each object to determine if it responds to a certain method. It is bad style to check the class of an object.
Instead, if you want to check that an object supports a selector you should use -respondsToSelector:, but only if you handle objects not responding to that selector.
I have the following method:
- (FDModel *)_modelForClass: (Class)modelClass
withIdentifier: (NSString *)identifier
which should take in a Class and a identifier, create an instance of modelClass, assign the identifier and do some other work based on the fact that it assumed modelClass is a subclass of FDModel.
I can put in a check that raises some error or exception if [modelClass isSubclassOfClass: [FDModel class]] == NO but I was trying to see if there was a way to enforce this at compile time.
EDIT: I understand that some people see this as a obvious factory method but the modelClass parameter is actually passed in by the user of my library through a delegate callback - (Class<FDModel>)modelClassForDictionary: (NSDictionary *)dictionary;. This question was more aimed at making the user of my library return a Class that has a specific subclass.
I would consider the plain answer to your question being no; there is no way of checking if a class passed as a parameter is of a certain kind.
But I'd like to argue that the essence of your question primarily points to a design issue, i.e. can't your instance-generating method be expressed as a factory method? Like so:
#interface FDModel
+ (instancetype)modelWithIdentifier:(NSString *)identifier;
#end
In the above case you would simply do:
[FDModel modelWithIdentifier:anIdentifier];
The actual class returned (and the initialisation logic) being specified by the factory method implementation through subclassing of the FDModel class:
#implementation FDModelSubclass
+ (instancetype)modelWithIdentifier:(NSString *)identifier
{
FDModel *model = [super modelWithIdentifier:identifier];
if (model)
{
// do additional init stuff
}
return model;
}
#end
Nothing to check, no chance to go wrong.
After some research I don't think you can do it at compile time - you have to do it at runtime as you expected.
BOOL classConformsToProtocol = [class conformsToProtocol:#protocol(OKAProtocol)];
OR
BOOL classConformsToProtocol = [self class:[OKAClass class] conformsToProtocol:#"OKAProtocol"];
------
- (BOOL)class:(Class)class conformsToProtocol:(NSString *)protocol;
{
return [class conformsToProtocol:NSProtocolFromString(protocol)];
}
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.
I've got an object of type id and would like to know if it contains a value for a given keyPath:
[myObject valueForKeyPath:myKeyPath];
Now, I wrap it into a #try{ } #catch{} block to avoid exceptions when the given keypath isn't found. Is there a nicer way to do this? Check if the given keypath exists without handling exceptions?
Thanks a lot,
Stefan
You could try this:
if ([myObject respondsToSelector:NSSelectorFromString(myKeyPath)])
{
}
However, that may not correspond to the getter you have, especially if it is a boolean value. If this doesn't work for you, let me know and I'll write you up something using reflection.
For NSManagedObjects, an easy solution is to look at the object's entity description and see if there's an attribute with that key name. If there is, you can also take it to the next step and see what type of an attribute the value is.
Here's a simple method that given any NSManagedObject and any NSString as a key, will always return an NSString:
- (NSString *)valueOfItem:(NSManagedObject *)item asStringForKey:(NSString *)key {
NSEntityDescription *entity = [item entity];
NSDictionary *attributesByName = [entity attributesByName];
NSAttributeDescription *attribute = attributesByName[key];
if (!attribute) {
return #"---No Such Attribute Key---";
}
else if ([attribute attributeType] == NSUndefinedAttributeType) {
return #"---Undefined Attribute Type---";
}
else if ([attribute attributeType] == NSStringAttributeType) {
// return NSStrings as they are
return [item valueForKey:key];
}
else if ([attribute attributeType] < NSDateAttributeType) {
// this will be all of the NSNumber types
// return them as strings
return [[item valueForKey:key] stringValue];
}
// add more "else if" cases as desired for other types
else {
return #"---Unacceptable Attribute Type---";
}
}
If the key is invalid or the value can't be made into a string, the method returns an NSString error message (change those blocks to do whatever you want for those cases).
All of the NSNumber attribute types are returned as their stringValue representations. To handle other attribute types (e.g.: dates), simply add additional "else if" blocks. (see NSAttributeDescription Class Reference for more information).
If the object is a custom class of yours, you could override valueForUndefinedKey: on your object, to define what is returned when a keypath doesn't exist.
It should be possible to graft this behavior onto arbitrary classes reasonably simply. I present with confidence, but without warranty, the following code which you should be able to use to add a non-exception-throwing implementation of valueForUndefinedKey: to any class, with one, centralized line of code per class at app startup time. If you wanted to save even more code, you could make all the classes you wanted to have this behavior inherit from a common subclass of NSManagedObject and then apply this to that common class and all your subclasses would inherit the behavior. More details after, but here's the code:
Header (NSObject+ValueForUndefinedKeyAdding.h):
#interface NSObject (ValueForUndefinedKeyAdding)
+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler;
#end
Implementation (NSObject+ValueForUndefinedKeyAdding.m):
#import "NSObject+ValueForUndefinedKeyAdding.h"
#import <objc/runtime.h>
#import <objc/message.h>
#implementation NSObject (ValueForUndefinedKeyAdding)
+ (void)addCustomValueForUndefinedKeyImplementation: (IMP)handler
{
Class clazz = self;
if (clazz == nil)
return;
if (clazz == [NSObject class] || clazz == [NSManagedObject class])
{
NSLog(#"Don't try to do this to %#; Really.", NSStringFromClass(clazz));
return;
}
SEL vfuk = #selector(valueForUndefinedKey:);
#synchronized([NSObject class])
{
Method nsoMethod = class_getInstanceMethod([NSObject class], vfuk);
Method nsmoMethod = class_getInstanceMethod([NSManagedObject class], vfuk);
Method origMethod = class_getInstanceMethod(clazz, vfuk);
if (origMethod != nsoMethod && origMethod != nsmoMethod)
{
NSLog(#"%# already has a custom %# implementation. Replacing that would likely break stuff.",
NSStringFromClass(clazz), NSStringFromSelector(vfuk));
return;
}
if(!class_addMethod(clazz, vfuk, handler, method_getTypeEncoding(nsoMethod)))
{
NSLog(#"Could not add valueForUndefinedKey: method to class: %#", NSStringFromClass(clazz));
}
}
}
#end
Then, in your AppDelegate class (or really anywhere, but it probably makes sense to put it somewhere central, so you know where to find it when you want to add or remove classes from the list) put this code which adds this functionality to classes of your choosing at startup time:
#import "MyAppDelegate.h"
#import "NSObject+ValueForUndefinedKeyAdding.h"
#import "MyOtherClass1.h"
#import "MyOtherClass2.h"
#import "MyOtherClass3.h"
static id ExceptionlessVFUKIMP(id self, SEL cmd, NSString* inKey)
{
NSLog(#"Not throwing an exception for undefined key: %# on instance of %#", inKey, [self class]);
return nil;
}
#implementation MyAppDelegate
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[MyOtherClass1 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
[MyOtherClass2 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
[MyOtherClass3 addCustomValueForUndefinedKeyImplementation: (IMP)ExceptionlessVFUKIMP];
});
}
// ... rest of app delegate class ...
#end
What I'm doing here is adding a custom implementation for valueForUndefinedKey: to the classes MyOtherClass1, 2 & 3. The example implementation I've provided just NSLogs and returns nil, but you can change the implementation to do whatever you want, by changing the code in ExceptionlessVFUKIMP. If you remove the NSLog, and just return nil, I suspect you'll get what you want, based on your question.
This code NEVER swizzles methods, it only adds one if it's not there. I've put in checks to prevent this from being used on classes that already have their own custom implementations of valueForUndefinedKey: because if someone put that method in their class, there's going to be an expectation that it will continue to get called. Also note that there may be AppKit code that EXPECTS the exceptions from the NSObject/NSManagedObject implementations to be thrown. (I don't know that for sure, but it's a possibility to consider.)
A few notes:
NSManagedObject provides a custom implementation for valueForUndefinedKey: Stepping through its assembly in the debugger, all it appears to do is throw roughly the same exception with a slightly different message. Based on that 5 minute debugger investigation, I feel like it ought to be safe to use this with NSManagedObject subclasses, but I'm not 100% sure -- there could be some behavior in there that I didn't catch. Beware.
Also, as it stands, if you use this approach, you don't have a good way to know if valueForKey: is returning nil because the keyPath is valid and the state happened to be nil, or if it's returning nil because the keyPath is invalid and the grafted-on handler returned nil. To do that, you'd need to do something different, and implementation specific. (Perhaps return [NSNull null] or some other sentinel value, or set some flag in thread-local storage that you could check, but at this point is it really all that much easier than #try/#catch?) Just something to be aware of.
This appears to work pretty well for me; Hope it's useful to you.
There's no easy way to solve this. Key Value Coding (KVC) isn't intended to be used that way.
One thing is for sure: using #try-#catch is really bad since you're very likely to leak memory etc. Exceptions in ObjC / iOS are not intended for normal program flow. They're also very expensive (both throwing and setting up the #try-#catch IIRC).
If you look at the Foundation/NSKeyValueCoding.h header, the comment / documentation for
- (id)valueForKey:(NSString *)key;
clearly states which methods need to be implemented for -valueForKey: to work. This may even use direct ivar access. You would have to check each one in the order described there. You need to take the key path, split it up based on . and check each part on each subsequent object. To access ivars, you need to use the ObjC runtime. Look at objc/runtime.h.
All of this is vary hacky, though. What you probably want is for your objects to implement some formal protocol and then check -conformsToProtocol: before calling.
Are your key paths random strings or are those strings under your control? What are you trying to achieve? Are you solving the wrong problem?
I don't believe this is possible in a safe way (i.e. without mucking with -valueForUndefinedKey: or something similar on other peoples' classes). I say that because on the Mac side of things, Cocoa Bindings—which can be set to substitute a default value for invalid key paths—simply catches the exceptions that result from bad key paths. If even Apple's engineers don't have a way to test if a key path is valid without trying it and catching the exception, I have to assume that such a way doesn't exist.
Working on a program that will record some things from the webcam when a user presses physical buttons connected to the mac via phidgets. Have call methods on other places in my app simply doing [self method: input], but on one place it doesn't work. What could be wrong?
This is the method i want to run if i get inputchange in my program.
Also i do -(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd; in my .h file.
-(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd {
//NSLog(#"phidget för port = %%d med signal %%d", ind, val);
if(inputVal == 1)
{
NSError* error;
NSFileManager* deleteMgr = [NSFileManager defaultManager];
NSString* path = #"/Users/Shared/tempFile.mov";
[deleteMgr removeItemAtPath:path error:&error];
[mCaptureMovieFileOutput recordToOutputFileURL:[NSURL fileURLWithPath:#"/Users/Shared/tempFile.mov"]];
}
else if(inputVal == 0)
{
[mCaptureMovieFileOutput recordToOutputFileURL:nil];
}
}
The code below give me result if imput from the buttons change. Here i just can't seem to call reportbutton2.
If i try to use [self reportButton2..] in gives me "Use of undeclared identifier 'self'"
int gotInputChange(CPhidgetInterfaceKitHandle phid, void *context, int ind, int val) {
what to do here?
return 0;
}
The problem is that gotInputChange is a C function not a Objective C method and so has no udea what self is as it does not belong to a class.
for [self reportButton2... = to work it needs to be a method in your class
I usually put something like this at the top of callbacks like gotInputChange:
MyObject *self = (id)context;
Then I can use self throughout the function as if it were a method.
The other thing being in a function makes harder is asserting conditions. The regular assertion macros, such as NSAssert and NSParameterAssert, require both of the implicit arguments to every method (self is one of them) to exist. In a C function, you must use NSCAssert, NSCParameterAssert, etc. instead.
You can also use your delegate.
SomeNameAppDelegate *delegate = (SomeNameAppDelegate *)[[NSApplication sharedApplication] delegate];
[delegate yourMethodName];
It works like in example if your target method in AppDelegate class. But when you have an access to delegate, you can create a pointers to necessary classes and use them over delegate.
Quickest but not soo nice way is to make your Class a singleton and access it from the gotInputChange function.
Okay thanks! Din't have any clue that it was C would never have solved it by myself. Did some googeling and this one did the trick for me.
[(id)context performSelectorOnMainThread:#selector(reportButton2:)withObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:ind], [NSNumber numberWithInt:val], nil] waitUntilDone:NO];