MacOS finding classes at launchtime - objective-c

Is there a way to determine which classes are present at launch time?
I have a Swift OS-X app that offers an API to add functionality. Not dynamically though, everything is fixed at launch time.
But is it possible to find out which classes are present at launch, and then from there to call a certain (inherited) static operation on these classes?
Absent this possibility I will have to create an initialisation routine that must be updated every time a new subclass is added. I would like to avoid this.
Clarification: I have a protocol call it MyProtocol. At launch of the App I would like to call an operation from MyProtocol on all classes that implement MyProtocol.
After examining the runtime manual I have gotten as far as:
#import <Foundation/Foundation.h>
#include "Test.h"
#import <objc/objc-class.h>
void activateLaunchActions() {
// Get a list of all classes
int numClasses = 0, newNumClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
while (numClasses < newNumClasses) {
numClasses = newNumClasses;
Class newClasses[numClasses];
classes = newClasses;
newNumClasses = objc_getClassList(classes, numClasses);
}
// Get the protocol they have to confirm to
Protocol *prot = objc_getProtocol("MyProtocol");
// Get the selector to be called
SEL sel = sel_registerName("launchAction");
// Create the launchAction caller from objc_msgSend
typedef void (*send_type)(Class, SEL);
send_type callLauchAction = (send_type)objc_msgSend;
// Call the registration for all classes that confirm to the protocol
for (int i=0; i<numClasses; i++) {
if (class_conformsToProtocol(classes[i], prot)) {
callLauchAction(classes[i], sel);
}
}
}
The "prot" is always NULL. Hence the test later fails and the launchAction is never called.
I have read that protocol objects are not always present if they are not used by a class, however this protocol is used by several classes.
Any suggestions as how to fix this would be welcome.

Related

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.

Objective-C - iVar Scoped Method Variables?

I was messing around in Objective-C earlier, and I ran into a quite common situation:
I had a class, which was not a singleton, that needed a variable shared between method calls, like static, but each instance needed it's own variable. However, this variable only needed to be used in one particular method, we'll call it -foo.
What I'd love to do, is have a macro, let's call it ivar, which lets me do the following:
#implementation MyClass
-(foo)
{
ivar int someVal = 10; // default value, ivar scoped variable.
}
-(bar)
{
someVal = 5; // error, outside of `foo`'s scope.
}
#end
How the variable is defined does not matter to me (either a macro like OBJC_IVAR(Type, Name, Default) or ivar someType someName = value), as long as it meets the following requirements:
Has thread safety
Can have variable of same name (but different value) in another method
Type-less (doesn't matter what type the variable is)
Default Value support
Variable can be declared in one line (I shouldn't have to write 15 lines of code just to put a variable in my code)
I am currently working on an Objective-C++ implementation myself, I was just wondering if anyone else had any thoughts (or existing tools) on how to do this.
Obviously, this doesn't have to be done with a true iVar. More likely, this should be done with associated objects at run-time, which also manages deallocation for us.
After a lot of time spent, I believe I have a fully working solution in Objective-C++. Some of the features:
The variables are unique. As long as they have a different scope, their values are independent
Each instance has it's own values
Thread safety (accomplished by associated objects)
Simple variable declaration:
Macro overloading: only specify the information that you need
Possible ways to define an OBJC_IVAR:
OBJC_IVAR(); // creates a warning, does nothing
OBJC_IVAR(Name); // creates an ivar named 'Name' of type 'id'
OBJC_IVAR(Type, Name); // creates an ivar named 'Name' of type 'Type'
OBJC_IVAR(Type, Name, Default); // creates an ivar named 'Name', of type 'Type', and a default value of 'Default' (which is only executed once);
Full Type Support with C++ templates (__weak, __strong, __autoreleasing, volatile, etc. are all supported)
Subclasses do not share variables with their superclasses (so no chance for conflicts, variables really are limited to their scope).
Can be used in singletons without issue
Is fast, takes ~15-30 CPU cycles to look up a variable, and once it's looked up, takes as long as any other variable to set it.
Most of the hard work is done by the pre-processor, which allows for faster code
Just drag-and-drop into an existing Xcode project, doesn't rely on a custom processor
Some minor cons to the implementation:
Objects must have an ownership specifier (limitation with C++ references: Reference to non-const type 'id' with no explicit ownership). Is easily fixed by adding __strong, __weak, or __autoreleasing to the type of the variable
Implementation is hard to read. Because it relies so much on C++ templates and Objective-C working together in harmony, it's difficult to just change 'one thing' and hope for it to work. I have added extensive comments to the implementation, so hopefully that frees some of the burden.
Method swizzling can confuse this majorly. Not the largest of issues, but if you start playing around with method swizzling, don't be surprised if you get unexpected results.
Cannot be used inside a C++ object. Unfortunately, C++ doesn't support runtime attributes, like objective-c does, so we cannot rely upon our variables being cleaned up eventually. For this reason, you cannot use OBJC_IVAR while inside a C++ object. I would be interested in seeing an implementation for that, though.
#line can mess this up drastically, so don't use it.
Version History
1.0: Initial Release
1.1: Updated OBJC_IVAR_NAME to rely only on the preprocessor. As a result, we cannot use __func__.
So, without further ado, here is the code:
OBJC_IVAR.hpp
//
// OBJC_IVAR.h
// TestProj
//
// Created by Richard Ross on 8/17/12.
// Copyright (c) 2012 Ultimate Computer Services, Inc. All rights reserved.
//
#ifndef OBJC_IVAR_HPP
#define OBJC_IVAR_HPP
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "NSValue+CppObject.h"
// Argument counting algorithm. Not too complex
#define __NARG(_1, _2, _3, _4, _5, VAL, ...) VAL
#define NARG(...) __NARG(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
// Different implementations based on number of parameters passed in
#define __OBJC_IVAR(N, ...) _OBJC_IVAR_ ## N (__VA_ARGS__)
#define _OBJC_IVAR(N, ...) __OBJC_IVAR(N, __VA_ARGS__)
// Usage: OBJC_IVAR(Type (optional), Name (required), Default (optional))
#define OBJC_IVAR(...) _OBJC_IVAR(NARG(__VA_ARGS__), __VA_ARGS__)
// create a unique name. we use '__COUNTER__' here to support scoping on the same line, for compressed source code
#define __OBJC_IVAR_STRINGIFY_NAME(file, line, name, counter) #file ":" #line " " #name ":" #counter
#define _OBJC_IVAR_NAME(file, line, name, counter) __OBJC_IVAR_STRINGIFY_NAME(file, line, name, counter)
#define OBJC_IVAR_NAME(name) _OBJC_IVAR_NAME(__FILE__, __LINE__, name, __COUNTER__)
// old style creation. advantage: uses __func__ to determine calling function
// #define OBJC_IVAR_NAME(Name) [NSString stringWithFormat:#"%s:%i %s:%s:%i", __FILE__, __LINE__, __func__, #Name, __COUNTER__]
// implemenations for each of the overloads
#define _OBJC_IVAR_0(...) _Pragma("message \"Cannot call OBJC_IVAR with 0 params!\"")
#define _OBJC_IVAR_1(Name) _OBJC_IVAR_2(__strong id, Name)
// first major implemenation. because we do no assignment here, we don't have to check for is_set
#define _OBJC_IVAR_2(Type, Name) Type& Name = (_OBJC_IVAR::IMPL<Type>(self, OBJC_IVAR_NAME(Name)))
// this is where things get fun. we have 'OBJC_IVAR_CUR_NAME', instead of calling OBJC_IVAR_NAME
// multiple times, because we must ensure that COUNTER does not change during the course of the macro
// this is the 'inner bowels' of C, and it's quite hacky. Returns a reference to an associated object
// which is wrapped in a NSValue. Note that we only evaluate 'default' once throught the course of the
// application's cycle, so you can feel free to put intensive loading code there.
static NSString *_OBJC_IVAR_CUR_NAME;
#define _OBJC_IVAR_3(Type, Name, Default) Type& Name = (_OBJC_IVAR::IS_SET(self, (_OBJC_IVAR_CUR_NAME = OBJC_IVAR_NAME(Name))) ? _OBJC_IVAR::IMPL<Type>(self, _OBJC_IVAR_CUR_NAME) : _OBJC_IVAR::IMPL<Type>(self, _OBJC_IVAR_CUR_NAME, Default))
// namespace to wrap al lof our functions
namespace _OBJC_IVAR
{
// internal dictionary of all associated object names, so that we don't run
// into memory management issues. we use a set here, because we should never
// have duplicate associated object names.
static NSMutableSet *_names = [NSMutableSet set];
// wraps a value and a reference to a value. used over std::reference_wrapper,
// as that doesn't actually copy in the value passed. That is required for what
// we are doing, as we cannot be assigning to constants.
template<typename T>
class Wrapper {
private:
// private value wrapped by this object.
T _value;
// private reference wrapped by this object. should always point to _value.
T& _ref;
public:
// default constructor. assumes 'T' has a valid 0-argument constructor
Wrapper() : _value(), _ref(_value) { }
// argument constructor. makes sure that value is initialized properly
Wrapper(T val) : _value(val), _ref(_value) { }
// returns the reference wrapped by this object
operator T& () {
return _ref;
}
T& get() {
return _ref;
}
};
// interns a name. because objc_getAssociatedObject works only by comparing
// pointers (and +stringWithFormat: isn't guaranteed to return the same pointer),
// we have to make sure that we maintain a list of all valid associated object
// names. these are NOT linked to specific objects, which allows us to reuse some
// memory
inline NSString *name_intern(NSString *name)
{
// intern the value. first check if the object has been interned already,
// and if it is, return that interned value
if (id tmpName = [_names member:name])
{
name = tmpName;
}
// if we haven't interned this value before, then add it to the list and return it.
else
{
[_names addObject:name];
}
return name;
}
// check and see if the requested iVar has been set yet. used for default value setting
BOOL IS_SET(id target, NSString *name)
{
// first intern the name
name = name_intern(name);
// check if the object has this property. objc_getAssociatedObject will ALWAYS
// return NULL if the object doesn't exist. Note the bridged cast. This is because
// objc_getAssociatedObject doesn't care what you throw into the second parameter,
// as long as it is a pointer. That gives us the flexibility at a later date, to,
// for example, just pass a pointer to a single byte, and pull out the value that
// way. However, we pass in a NSString pointer, because it makes it easy for us to
// use and to re-use later.
id val = objc_getAssociatedObject(target, (__bridge const void *) name);
return val != nil;
}
// the actual implementation for setting the iVar. luckily this code isn't too hacky,
// but it is a bit confusing.
template<typename T>
Wrapper<T>& IMPL(id target, NSString *name)
{
// first intern the name
name = name_intern(name);
// define a reference. we use pointers & new here, because C++ memory managment is
// weird at best. Most of the time, you should be using RAII, but when dealing with
// templates & objective-c interpolation, it is almost required that you use pointers
// with new.
Wrapper<T> *reference = nullptr;
// check and see if the object already contains this property, if so, return that value
NSValue *result = objc_getAssociatedObject(target, (__bridge const void *) name);
if (result == nil)
{
// at this point, we need to create a new iVar, with the default constructor for the type.
// for objective-c objects this is 'nil', for integers and floating point values this is 0,
// for C++ structs and classes, this calls the default constructor. If one doesn't exist,
// you WILL get a compile error.
reference = new Wrapper<T>();
// we now set up the object that will hold this wrapper. This is an extension on NSValue
// which allows us to store a generic pointer (in this case a C++ object), and run desired
// code on -dealloc (which will be called at the time the parent object is destroyed), in
// this case, free the memory used by our wrapper.
result = [NSValue valueWithCppObject:reference onDealloc:^(void *) {
delete reference;
}];
// finally, set the associated object to the target, and now we are good to go.
// We use OBJC_ASSOCIATION_RETAIN, so that our NSValue is properly freed when done.
objc_setAssociatedObject(target, (__bridge const void *) name, result, OBJC_ASSOCIATION_RETAIN);
}
// from result, we cast it's -cppObjectValue to a Wrapper, to pull out the value.
reference = static_cast<Wrapper<T> *>([result cppObjectValue]);
// finally, return the pointer as a reference, not a pointer
return *reference;
}
// this is pretty much the same as the other IMPL, but it has specific code for default values.
// I will ignore everything that is the same about the two functions, and only focus on the
// differences, which are few, but mandatory.
template<typename T>
Wrapper<T>& IMPL(id target, NSString *name, const T& defVal)
{
name = name_intern(name);
Wrapper<T> *reference = nullptr; // asign to be the default constructor for 'T'
NSValue *result = objc_getAssociatedObject(target, (__bridge const void *) name);
if (result == nil)
{
// this is the only difference. Instead of constructing with the default constructor,
// simply pass in our new default value as a copy.
reference = new Wrapper<T>(defVal);
result = [NSValue valueWithCppObject:reference onDealloc:^(void *) {
delete reference;
}];
objc_setAssociatedObject(target, (__bridge const void *) name, result, OBJC_ASSOCIATION_RETAIN);
}
reference = static_cast<Wrapper<T> *>([result cppObjectValue]);
return *reference;
}
}
#endif // OBJC_IVAR_HPP
NSValue+CppObject.h
//
// NSValue+CppObject.h
// TestProj
//
// Created by Richard Ross on 8/17/12.
// Copyright (c) 2012 Ultimate Computer Services, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
// Extension on NSValue to add C++ object support. Because of the difficulty
// involved in templates, I took the easy way out and simply passed in a block
// of code to be run at dealloc.
#interface NSValue (CppObject)
// create a new NSValue instance that holds ptr, and calls 'deallocBlock' on destruction.
+(id) valueWithCppObject:(void *) ptr onDealloc:(void (^)(void *)) deallocBlock;
-(id) initWithCppObject:(void *) ptr onDealloc:(void (^)(void *)) deallocBlock;
// get the held pointer of this object. I called it -cppObjectValue, so
// there was no confusion with -pointerValue.
-(void *) cppObjectValue;
#end
NSValue+CppObject.m
//
// NSValue+CppObject.m
// TestProj
//
// Created by Richard Ross on 8/17/12.
// Copyright (c) 2012 Ultimate Computer Services, Inc. All rights reserved.
//
#import "NSValue+CppObject.h"
// the concrete NSValue subclass for supporting C++ objects. Pretty straight-forward interface.
#interface ConcreteCppObject : NSValue
{
// the underlying object that is being pointed to
void *_object;
// the block that is called on -dealloc
void (^_deallocBlock)(void *);
}
#end
#implementation ConcreteCppObject
// object initialization
+(id) valueWithCppObject:(void *)ptr onDealloc:(void (^)(void *))deallocBlock
{
return [[self alloc] initWithCppObject:ptr onDealloc:deallocBlock];
}
-(id) initWithCppObject:(void *)ptr onDealloc:(void (^)(void *))deallocBlock
{
if (self = [super init])
{
_object = ptr;
_deallocBlock = deallocBlock;
}
return self;
}
// required methods for subclassing NSValue
-(const char *) objCType
{
return #encode(void *);
}
-(void) getValue:(void *)value
{
*((void **) value) = _object;
}
// comparison
-(BOOL) isEqual:(id)compare
{
if (![compare isKindOfClass:[self class]])
return NO;
return [compare cppObjectValue] == [self cppObjectValue];
}
// cleanup
-(void) dealloc
{
// this should manage cleanup for us
_deallocBlock(_object);
}
// value access
-(void *) cppObjectValue
{
return _object;
}
#end
// NSValue additions for creating the concrete instances
#implementation NSValue (CppObject)
// object initialization
+(id) valueWithCppObject:(void *)ptr onDealloc:(void (^)(void *))deallocBlock
{
return [[ConcreteCppObject alloc] initWithCppObject:ptr onDealloc:deallocBlock];
}
-(id) initWithCppObject:(void *)ptr onDealloc:(void (^)(void *))deallocBlock
{
return [[self class] valueWithCppObject:ptr onDealloc:deallocBlock];
}
// unless the NSValue IS a ConcreteCppObject, then we shouldn't do anything here
-(void *) cppObjectValue
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
#end
Example Usage:
#import "OBJC_IVAR.hpp"
#interface SomeObject : NSObject
-(void) doSomething;
#end
#implementation SomeObject
-(void) doSomething
{
OBJC_IVAR(__strong id, test, #"Hello World!");
OBJC_IVAR(int, test2, 15);
NSLog(#"%#", test);
NSLog(#"%i", test2 += 7);
// new scope
{
OBJC_IVAR(int, test, 100);
NSLog(#"%i", ++test);
}
[self somethingElse];
}
-(void) somethingElse
{
OBJC_IVAR(int, newVar, 7);
NSLog(#"%i", newVar++);
}
#end
int main()
{
SomeObject *obj = [SomeObject new];
[obj doSomething];
[obj doSomething];
[obj doSomething];
}
I had a class, which was not a singleton, that needed a variable
shared between method calls, like static, but each instance needed
it's own variable.
In that case, the variable is part of the object's state, and it's therefore most appropriate to use an instance variable (or a property). This is exactly what ivars are for, whether they're used in a dozen methods or just one.
I am currently working on an Objective-C++ implementation myself, I
was just wondering if anyone else had any thoughts (or existing tools)
on how to do this.
My advice is to not do it at all. If your goal is to avoid clutter, don't go needlessly trying to add a new storage class to the language.
However, if you're determined to pursue this line, I'd look at using blocks instead of associated objects. Blocks get their own copies of variables that are scoped to the lifetime of the block. For example, you can do this:
- (void)func
{
__block int i = 0;
void (^foo)() = ^{
i++;
NSLog(#"i = %d", i);
};
foo();
foo();
foo();
}
and the output you get is:
i = 1
i = 2
i = 3
Perhaps you can find a clever way to wrap that up in a macro, but it looks to me like a lot of trouble just to avoid declaring an instance variable.

How to write iOS app purely in C

I read here Learn C Before Objective-C?
Usually I then replace some Obj-C code with pure C code (after all you can mix them as much as you like, the content of an Obj-C method can be entirely, pure C code)
Is this true?
Is it possible to build an iPhone app purely in the C programming language?
Damn, it took me a while but I got it:
main.c:
#include <CoreFoundation/CoreFoundation.h>
#include <objc/runtime.h>
#include <objc/message.h>
// This is a hack. Because we are writing in C, we cannot out and include
// <UIKit/UIKit.h>, as that uses Objective-C constructs.
// however, neither can we give the full function declaration, like this:
// int UIApplicationMain (int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
// So, we rely on the fact that for both the i386 & ARM architectures,
// the registers for parameters passed in remain the same whether or not
// you are using VA_ARGS. This is actually the basis of the objective-c
// runtime (objc_msgSend), so we are probably fine here, this would be
// the last thing I would expect to break.
extern int UIApplicationMain(int, ...);
// Entry point of the application. If you don't know what this is by now,
// then you probably shouldn't be reading the rest of this post.
int main(int argc, char *argv[])
{
// Create an #autoreleasepool, using the old-stye API.
// Note that while NSAutoreleasePool IS deprecated, it still exists
// in the APIs for a reason, and we leverage that here. In a perfect
// world we wouldn't have to worry about this, but, remember, this is C.
id autoreleasePool = objc_msgSend(objc_msgSend(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")), sel_registerName("init"));
// Notice the use of CFSTR here. We cannot use an objective-c string
// literal #"someStr", as that would be using objective-c, obviously.
UIApplicationMain(argc, argv, nil, CFSTR("AppDelegate"));
objc_msgSend(autoreleasePool, sel_registerName("drain"));
}
AppDelegate.c:
#import <objc/runtime.h>
#import <objc/message.h>
// This is equivalent to creating a #class with one public variable named 'window'.
struct AppDel
{
Class isa;
id window;
};
// This is a strong reference to the class of the AppDelegate
// (same as [AppDelegate class])
Class AppDelClass;
// this is the entry point of the application, same as -application:didFinishLaunchingWithOptions:
// note the fact that we use `void *` for the 'application' and 'options' fields, as we need no reference to them for this to work. A generic id would suffice here as well.
BOOL AppDel_didFinishLaunching(struct AppDel *self, SEL _cmd, void *application, void *options)
{
// we +alloc and -initWithFrame: our window here, so that we can have it show on screen (eventually).
// this entire method is the objc-runtime based version of the standard View-Based application's launch code, so nothing here really should surprise you.
// one thing important to note, though is that we use `sel_getUid()` instead of #selector().
// this is because #selector is an objc language construct, and the application would not have been created in C if I used #selector.
self->window = objc_msgSend(objc_getClass("UIWindow"), sel_getUid("alloc"));
self->window = objc_msgSend(self->window, sel_getUid("initWithFrame:"), (struct CGRect) { 0, 0, 320, 480 });
// here, we are creating our view controller, and our view. note the use of objc_getClass, because we cannot reference UIViewController directly in C.
id viewController = objc_msgSend(objc_msgSend(objc_getClass("UIViewController"), sel_getUid("alloc")), sel_getUid("init"));
// creating our custom view class, there really isn't too much
// to say here other than we are hard-coding the screen's bounds,
// because returning a struct from a `objc_msgSend()` (via
// [[UIScreen mainScreen] bounds]) requires a different function call
// and is finicky at best.
id view = objc_msgSend(objc_msgSend(objc_getClass("View"), sel_getUid("alloc")), sel_getUid("initWithFrame:"), (struct CGRect) { 0, 0, 320, 480 });
// here we simply add the view to the view controller, and add the viewController to the window.
objc_msgSend(objc_msgSend(viewController, sel_getUid("view")), sel_getUid("addSubview:"), view);
objc_msgSend(self->window, sel_getUid("setRootViewController:"), viewController);
// finally, we display the window on-screen.
objc_msgSend(self->window, sel_getUid("makeKeyAndVisible"));
return YES;
}
// note the use of the gcc attribute extension (constructor).
// Basically, this lets us run arbitrary code before program startup,
// for more information read here: http://stackoverflow.com/questions/2053029
__attribute__((constructor))
static void initAppDel()
{
// This is objc-runtime gibberish at best. We are creating a class with the
// name "AppDelegate" that is a subclass of "UIResponder". Note we do not need
// to register for the UIApplicationDelegate protocol, that really is simply for
// Xcode's autocomplete, we just need to implement the method and we are golden.
AppDelClass = objc_allocateClassPair(objc_getClass("UIResponder"), "AppDelegate", 0);
// Here, we tell the objc runtime that we have a variable named "window" of type 'id'
class_addIvar(AppDelClass, "window", sizeof(id), 0, "#");
// We tell the objc-runtime that we have an implementation for the method
// -application:didFinishLaunchingWithOptions:, and link that to our custom
// function defined above. Notice the final parameter. This tells the runtime
// the types of arguments received by the function.
class_addMethod(AppDelClass, sel_getUid("application:didFinishLaunchingWithOptions:"), (IMP) AppDel_didFinishLaunching, "i#:##");
// Finally we tell the runtime that we have finished describing the class and
// we can let the rest of the application use it.
objc_registerClassPair(AppDelClass);
}
View.c
#include <objc/runtime.h>
// This is a strong reference to the class of our custom view,
// In case we need it in the future.
Class ViewClass;
// This is a simple -drawRect implementation for our class. We could have
// used a UILabel or something of that sort instead, but I felt that this
// stuck with the C-based mentality of the application.
void View_drawRect(id self, SEL _cmd, struct CGRect rect)
{
// We are simply getting the graphics context of the current view,
// so we can draw to it
CGContextRef context = UIGraphicsGetCurrentContext();
// Then we set it's fill color to white so that we clear the background.
// Note the cast to (CGFloat []). Otherwise, this would give a warning
// saying "invalid cast from type 'int' to 'CGFloat *', or
// 'extra elements in initializer'. Also note the assumption of RGBA.
// If this wasn't a demo application, I would strongly recommend against this,
// but for the most part you can be pretty sure that this is a safe move
// in an iOS application.
CGContextSetFillColor(context, (CGFloat []){ 1, 1, 1, 1 });
// here, we simply add and draw the rect to the screen
CGContextAddRect(context, (struct CGRect) { 0, 0, 320, 480 });
CGContextFillPath(context);
// and we now set the drawing color to red, then add another rectangle
// and draw to the screen
CGContextSetFillColor(context, (CGFloat []) { 1, 0, 0, 1 });
CGContextAddRect(context, (struct CGRect) { 10, 10, 20, 20 });
CGContextFillPath(context);
}
// Once again we use the (constructor) attribute. generally speaking,
// having many of these is a very bad idea, but in a small application
// like this, it really shouldn't be that big of an issue.
__attribute__((constructor))
static void initView()
{
// Once again, just like the app delegate, we tell the runtime to
// create a new class, this time a subclass of 'UIView' and named 'View'.
ViewClass = objc_allocateClassPair(objc_getClass("UIView"), "View", 0);
// and again, we tell the runtime to add a function called -drawRect:
// to our custom view. Note that there is an error in the type-specification
// of this method, as I do not know the #encode sequence of 'CGRect' off
// of the top of my head. As a result, there is a chance that the rect
// parameter of the method may not get passed properly.
class_addMethod(ViewClass, sel_getUid("drawRect:"), (IMP) View_drawRect, "v#:");
// And again, we tell the runtime that this class is now valid to be used.
// At this point, the application should run and display the screenshot shown below.
objc_registerClassPair(ViewClass);
}
It's ugly, but it works.
If you would like to download this, you can get it from my dropbox here
You can get it from my GitHub repository here:
Objective-C is a superset of the C-language, so it is theoretically possible to write a program entirely in C, however, unless you are thoroughly versed in OpenGL ES, You'll need to do at least some objC (Even Rich's sample has a const NSString* in it), else you'll have to write the views yourself.
OK, the above is completely wrong. Let me say, I'm astounded Rich achieved this lofty goal, so I ported it over to the mac (source here). The files below have no headers, do not link to Cocoa, nor does the project have a nib:
AppDelegate.m
#include <objc/runtime.h>
#include <objc/message.h>
extern id NSApp;
struct AppDel
{
Class isa;
//Will be an NSWindow later, for now, it's id, because we cannot use pointers to ObjC classes
id window;
};
// This is a strong reference to the class of the AppDelegate
// (same as [AppDelegate class])
Class AppDelClass;
BOOL AppDel_didFinishLaunching(struct AppDel *self, SEL _cmd, id notification) {
//alloc NSWindow
self->window = objc_msgSend(objc_getClass("NSWindow"),
sel_getUid("alloc"));
//init NSWindow
//Adjust frame. Window would be about 50*50 px without this
//specify window type. We want a resizeable window that we can close.
//use retained backing because this thing is small anyhow
//return no because this is the main window, and should be shown immediately
self->window = objc_msgSend(self->window,
sel_getUid("initWithContentRect:styleMask:backing:defer:"),(NSRect){0,0,1024,460}, (NSTitledWindowMask|NSClosableWindowMask|NSResizableWindowMask|NSMiniaturizableWindowMask),NSBackingStoreRetained,NO);
//send alloc and init to our view class. Love the nested objc_msgSends!
id view = objc_msgSend(objc_msgSend(objc_getClass("View"), sel_getUid("alloc")), sel_getUid("initWithFrame:"), (struct CGRect) { 0, 0, 320, 480 });
// here we simply add the view to the window.
objc_msgSend(self->window, sel_getUid("setContentView:"), view);
objc_msgSend(self->window, sel_getUid("becomeFirstResponder"));
//makeKeyOrderFront: NSWindow to show in bottom left corner of the screen
objc_msgSend(self->window,
sel_getUid("makeKeyAndOrderFront:"),
self);
return YES;
}
static void initAppDel()
{
//Our appDelegate should be NSObject, but if you want to go the hard route, make this a class pair of NSApplication and try initing those awful delegate methods!
AppDelClass = objc_allocateClassPair((Class)
objc_getClass("NSObject"), "AppDelegate", 0);
//Change the implementation of applicationDidFinishLaunching: so we don't have to use ObjC when this is called by the system.
class_addMethod(AppDelClass,
sel_getUid("applicationDidFinishLaunching:"),
(IMP) AppDel_didFinishLaunching, "i#:#");
objc_registerClassPair(AppDelClass);
}
void init_app(void)
{
objc_msgSend(
objc_getClass("NSApplication"),
sel_getUid("sharedApplication"));
if (NSApp == NULL)
{
fprintf(stderr,"Failed to initialized NSApplication... terminating...\n");
return;
}
id appDelObj = objc_msgSend(
objc_getClass("AppDelegate"),
sel_getUid("alloc"));
appDelObj = objc_msgSend(appDelObj, sel_getUid("init"));
objc_msgSend(NSApp, sel_getUid("setDelegate:"), appDelObj);
objc_msgSend(NSApp, sel_getUid("run"));
}
//there doesn't need to be a main.m because of this little beauty here.
int main(int argc, char** argv)
{
//Initialize a valid app delegate object just like [NSApplication sharedApplication];
initAppDel();
//Initialize the run loop, just like [NSApp run]; this function NEVER returns until the app closes successfully.
init_app();
//We should close acceptably.
return EXIT_SUCCESS;
}
View.m
#include <objc/runtime.h>
#include <objc/message.h>
#include <ApplicationServices/ApplicationServices.h>
// This is a strong reference to the class of our custom view,
// In case we need it in the future.
Class ViewClass;
// This is a simple -drawRect implementation for our class. We could have
// used a UILabel or something of that sort instead, but I felt that this
// stuck with the C-based mentality of the application.
void View_drawRect(id self, SEL _cmd, CGRect rect)
{
//make a red NSColor object with its convenience method
id red = objc_msgSend(objc_getClass("NSColor"), sel_getUid("redColor"));
// fill target rect with red, because this is it!
NSRect rect1 = NSMakeRect ( 21,21,210,210 );
objc_msgSend(red, sel_getUid("set"));
NSRectFill ( rect1 );
}
// Once again we use the (constructor) attribute. generally speaking,
// having many of these is a very bad idea, but in a small application
// like this, it really shouldn't be that big of an issue.
__attribute__((constructor))
static void initView()
{
// Once again, just like the app delegate, we tell the runtime to
// create a new class, this time a subclass of 'UIView' and named 'View'.
ViewClass = objc_allocateClassPair((Class) objc_getClass("NSView"), "View", 0);
// and again, we tell the runtime to add a function called -drawRect:
// to our custom view. Note that there is an error in the type-specification
// of this method, as I do not know the #encode sequence of 'CGRect' off
// of the top of my head. As a result, there is a chance that the rect
// parameter of the method may not get passed properly.
class_addMethod(ViewClass, sel_getUid("drawRect:"), (IMP) View_drawRect, "v#:");
// And again, we tell the runtime that this class is now valid to be used.
// At this point, the application should run and display the screenshot shown below.
objc_registerClassPair(ViewClass);
}
prefix.pch
//
// Prefix header for all source files of the 'CBasedMacApp' target in the 'CBasedMacApp' project
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#endif
I read here Learn C Before Objective-C?
Usually I then replace some Obj-C code with pure C code (after all you can mix them as much as you like, the content of an Obj-C method can be entirely, pure C code)
Is this true?
Could I build an iPhone app purely in the C programming language?
The quoted passage is true, but the answer to your question is no.
To illustrate what answerer Mecki on that other question was talking about:
- (void) drawRect:(CGRect)dirtyRect { //Objective-C
CGContextRef context = UIGraphicsGetCurrentContext(); //C
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0); //C
CGContextFillRect(context, dirtyRect); //C
} //Objective-C (balances above “- (void) drawRect:…” line)
There is nothing but pure C code within this method, but the method itself is Objective-C code, as is the class that contains this method.
So it is possible to do what Mecki said, but you can't (practically—as Richard J. Ross III showed, it's technically possible but quite a lot of typing) write a whole Cocoa Touch program in pure C.
Actually, some of the code posted here, while written in C, is still calling objective-C code :). I don't know if that actually fits the scenario from the original poster when he asked
Is it possible to build an iPhone app purely in the C programming
language?
but I would agree with the people saying that, generally speaking and for an app with a GUI, you would need to write your GUI in OpenGL (which is C).
I think that is what most games do, right? Although I'm not sure if there's access to the iPhone's I/O (the touchscreen for example) in C.
Last but not least, the guys that wrote the code above rock! :)

Managing list of error codes for NSError in objective c

In Cocoa and Objective C the favorite method for managing error seems to be using an NSError * object, to construct an error object however, we need to call the following method
+ (id)errorWithDomain:(NSString *)domain code:(NSInteger)code userInfo:(NSDictionary *)dict
My question is, what are some of the best practices for managing error domain, error code definitions and user info dictionary across the entire application so that error code, domain and user info dict always stays consistent?
If you have a hefty amount of error construction, your life could be much simpler by using a class. I actually use C++ for this so the calls a program does not need may be removed (unlike objc), but you can use C, ObjC, or C++ for this:
MONErrorDomain.h
// you won't normally need an instance here
#interface MONErrorDomain : NSObject
+ (NSString *)domain; // << required override
- (NSString *)domain; // << returns [[self class] domain]
// example convenience methods:
// uses [self domain]
+ (NSError *)errorWithErrorCode:(NSInteger)errorCode; // << user info would be nil
+ (NSError *)errorWithErrorCode:(NSInteger)errorCode userInfo:(NSDictionary *)userInfo;
#end
MONKoalaError.h
#interface MONKoalaError : MONErrorDomain
+ (NSError *)outOfEucalyptus;
#end
extern NSString * const MONKoalaErrorDomain;
typedef enum MONKoalaErrorCode {
MONKoalaErrorCode_Undefined = 0,
MONKoalaErrorCode_OutOfEucalyptus
} MONKoalaErrorCode;
MONKoalaError.m
// apple recommends we use reverse domains
NSString * const MONKoalaErrorDomain = #"com.mon.koala-library.MONKoalaErrorDomain";
#implementation MONKoalaError
+ (NSString *)domain
{
return MONKoalaErrorDomain;
}
+ (NSError *)outOfEucalyptus
{
NSDictionary * info = …;
return [self errorWithErrorCode:MONKoalaErrorCode_OutOfEucalyptus userInfo:info];
}
#end
Then the error creation is all in one place for each domain, and the clients can easily pick their errors without actually building them manually:
if (outError) {
*outError = [MONKoalaError outOfEucalyptus];
}
and error handling takes the form:
if ([e.domain isEqualToString:MONKoalaErrorDomain]) {
switch (e.code) {
case MONKoalaErrorCode_OutOfEucalyptus : {
self.needsEucalyptus = true;
…
One common way is to define some appropriate constants in a header file, and then include that header file wherever needed. It's a pretty simple approach, and looks like:
const NSString * kMyAppErrorDomain = #"com.example.myapp";
const NSInteger kMyAppSomeError = 2;
// key into user info dictionary
const NSString * kMyAppProblemKey = #"MyAppProblemKey";
I've also seen some applications which create convenience methods for creating these, either as a category on NSError or as a separate utility class or set of functions. It's also entirely reasonable to subclass NSError, for example to customize the localized description.
If you have not already seen it, Apple has released the Error Handling Programming Guide which discusses how these should be used in Cocoa.

Objective-C: Get list of subclasses from superclass

In Objective-C is there a way to ask a Class if there are any Subclass implementations.
I have a Base class which has multiple subclasses. I would like to loop through all the subclasses and perform a class selector on each of them.
Edit:
I have a set of classes that can process certain types of data. Each of the processors subclass a base class that provides methods that each processor needs.
Each class knows what data it can process and some classes can process certain types of data better than others.
I would like to have a class method on each class that would provide a response back to a factory class that says yes i can process that data, and give a indication of how well it can process it.
The factory would then make the decision on which class to instantiate based on which class says it can process the data the best.
I have also found this question from 2009 (I did search before I posted this but didn't find anything) Discover subclasses of a given class in Obj-C.
Edit 2:
The + (void)load method looks to be the perfect solution to what I am looking for. So I now have the following:
+ (void)registerSubclass:(Class)subclass {
NSLog(#"Registered %#", subclass);
}
In my base class the this is my subs.
+(void)load {
[BaseSwitch registerSubclass:[self class]];
}
This now displays a debug message for each of the subclasses.
My next question is (probably a stupid one), how do I store the classes that get registered in the registerSubclass method. Is there a way to have class variable that I can read later?
Edit 3:
Found some example code here A simple, extensible HTTP server in Cocoa
Which has left me with the following, seems pretty simple after all is said and done. But I thought I would put it here for future reference.
#implementation BaseSwitch
static NSMutableArray *registeredSubclasses;
+ (void)registerSubclass:(Class)subclass {
if (registeredSubclasses == nil) {
registeredSubclasses = [[NSMutableArray alloc] init];
}
[registeredSubclasses addObject:subclass];
NSLog(#"Registered %#", subclass);
}
+ (void)logSubclasses {
for (int i = 0; i < [registeredSubclasses count]; i++) {
NSLog(#"%#", [registeredSubclasses objectAtIndex:i]);
}
}
#end
Thanks for everyones suggestions, I will leave the question unanswered for a couple more days incase something else comes up.
This function gives you all subclasses of a class:
#import <objc/runtime.h>
NSArray *ClassGetSubclasses(Class parentClass)
{
int numClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
NSMutableArray *result = [NSMutableArray array];
for (NSInteger i = 0; i < numClasses; i++)
{
Class superClass = classes[i];
do
{
superClass = class_getSuperclass(superClass);
} while(superClass && superClass != parentClass);
if (superClass == nil)
{
continue;
}
[result addObject:classes[i]];
}
free(classes);
return result;
}
Taken from Cocoa with Love.
The example from Cocoa with Love can lead to EXC_I386_GPFLT, which stands for General Protection Fault. Instead of the do while loop, we should use a normal while loop to check if the superClass is valid.
#import <objc/runtime.h>
NSArray * ClassGetSubclasses(Class parentClass)
{
int numClasses = objc_getClassList(NULL, 0);
// According to the docs of objc_getClassList we should check
// if numClasses is bigger than 0.
if (numClasses <= 0) {
return [NSMutableArray array];
}
int memSize = sizeof(Class) * numClasses;
Class *classes = (__unsafe_unretained Class *)malloc(memSize);
if (classes == NULL && memSize) {
return [NSMutableArray array];
}
numClasses = objc_getClassList(classes, numClasses);
NSMutableArray<Class> *result = [NSMutableArray new];
for (NSInteger i = 0; i < numClasses; i++) {
Class superClass = classes[i];
// Don't add the parent class to list of sublcasses
if (superClass == parentClass) {
continue;
}
// Using a do while loop, like pointed out in Cocoa with Love,
// can lead to EXC_I386_GPFLT, which stands for General
// Protection Fault and means we are doing something we
// shouldn't do. It's safer to use a regular while loop to
// check if superClass is valid.
while (superClass && superClass != parentClass) {
superClass = class_getSuperclass(superClass);
}
if (superClass) {
[result addObject:classes[i]];
}
}
free(classes);
return result;
}
Check out the following GitHub issues for reference:
Sentry Cocoa
One Signal iOS SDK
You can never list subclasses of a class. In (almost) any programming language. This is one of the basic properties of Object Oriented Programming.
Consider changing your object model.
What you probably want is to create an abstract class and different subclasses but you shouldn't access the subclasses from the abstract class. You should create another object (Factory class) which registers the subclasses and selects the appropiate one when needed.
Note that you cannot efficiently register a class from the class itself. For a class code to be executed, the class has to be loaded first. That means, you have to import its header in some other class and that means that you are actually registering the class by importing its header.
There are two possible solutions:
Your factory class has to know the names of all subclasses (either at compile time or reading some configuration file).
Your factory class has a method to which anyone can pass the name of a class to be registered. This is the right solution if you want external libraries to register a new subclass. Then you can put the subclass registration code into the main header of the library.