I have a c++ static libray: .a file and staticLibrary.h file.
In the .h file, there is a class I want to access:
typedef enum
{
eStaticLibOperationUnknown = 0
eStaticLibOperationSystemCheck = 1
} enumStaticLibOperation;
typedef enum
{
eStaticLibResultUnknown = 0,
eStaticLibResultNullParameter = 4,
eStaticLibResultWrongParameter = 5
} enumStaticLibResult;
typedef std::function<void(void)> typeCallBack;
class classResultHelper
{
blah blah
};
class staticLibrary
{
public:
staticLibrary(typeCallBack, const char*);
void requestOperation(const char*, size_t);
void requestOperation(enumStaticLibOperation, const char*, size_t);
enumStaticLibResult getResult(char**, size_t*);
};
I used #import "staticLibrary.h" at the top of my viewController.m file. This raised an error as it recognized the C++ to be foreign. I then changed the viewController to a .mm extension, making the file Objective-C++ and removing the error.
But when I try to run staticLibrary* sL = [[staticLibrary alloc] init]; in viewDidLoad, I get an error at the second staticLibrary on the right side. It says "receiver type is not an objective-c class". What am I doing wrong?
When looking at the documentation for using the static library it says:
1.1. new staticLibrary(callback, “en”);
1.2. requestOperation(“enumSystemcheck”, NULL, 0);
1.3. callback();
1.4. getResult(... , ...);"
I believe this is Java (?), and the first line is to make an instance of staticLibrary with those parameters. How would I do that in objective-C?
The code you have in the example isn't Java, it's C++. ObjC++ means that you can mix statements made in C++ or ObjC on a line, it doesn't mean you can use C++ objects as if they were ObjC objects, or with the ObjC syntax.
What people usually do is only include C++ headers and write C++ code in the .mm file itself, and not put any in the header. Write an ObjC class that wraps the part of your C++ library that you want. So in your example, that'd be something like:
JCRStaticLibrary.h
#interface JCRStaticLibrary : NSObject
-(instancetype) initWithCallback: (void(^)(void))inObjCCallback;
-(void) requestOperation: (NSString*)what withBuffer: (void*)buf size: (int)theSize;
#end
JCRStaticLibrary.mm
#import "JCRStaticLibrary.h"
#include "staticLibrary.h"
#interface JCRStaticLibrary ()
{
staticLibrary *_cppStaticLibrary;
}
#end
#implementation JCRStaticLibrary
-(instancetype) initWithCallback: (void(^)(void))inObjCCallback
{
self = [super init];
if( self )
{
_staticLibrary = new staticLibrary( inObjCCallback, "en"); // ObjC++ knows how to turn an ObjC block into a C++ lambda.
// Under the hood it generates code like:
// _staticLibrary = new staticLibrary( [inObjCCallback](){ inObjCCallback(); }, "en");
// Where the [inObjCCallback](){} part is how C++ does lambdas, its equivalent to blocks.
// I.e. it's roughly analogous to ObjC's ^(){}.
}
}
-(void) dealloc
{
delete _staticLibrary;
}
-(void) requestOperation: (NSString*)what withBuffer: (void*)buf size: (int)theSize
{
_staticLibrary->requestOperation( [what UTF8String], buf, theSize );
}
#end
Something like that. I don't know what the parameters to requestOperation in your case actually are, so I just made an educated guess.
Instead of passing in the ObjC block to -initWithCallback:, you could also write your own lambda and make it a method, i.e.:
-(instancetype) init
{
__weak JCRStaticLibrary *weakSelf = self; // Avoid retain circle.
_staticLibrary = new staticLibrary( [weakSelf](){ [weakSelf doCallbackThing]; }, "en"); // ObjC++ knows how to turn an ObjC block into a C++ lambda.
}
-(void) doCallbackThing
{
// Do whatever the callback should do here.
}
It really depends on whether the callback changes every time you create an object of this type (e.g. if a JCRStaticLibrary object represents a command sent over the network) or comes from a small set of commands used over and over again (e.g. you receive a video frame and apply a filter to it, then hand it off to another object, so you really only ever have one callback). In the former case you wanna keep the block, in the latter, having a subclass for each filter might make more sense (unless you want to switch between filters on-the-fly).
Related
I have a chunk of code written in C that is pulling data from a device, that code can be viewed Here
I want this code which contains a function called getData to be run as method (called getData) of an Objective-C class rather than just having it run from inside the main() C function as it does now while I test it out. My goal is for this method to populate a public global variable variable or even just an class property with a base64 encoded string and return a status.
Here Is how I'm currently setting this up, but this is also my first time writing both C and Objective-C so to be honest I'm not sure if my approach is correct. First I create an interface(protocol) called GDDriver.h
//GDDriver.h
typedef enum Status : NSInteger {
Success,
Cancelled,
DeviceNotFound,
DeviceError,
UnkownModel,
} Status;
#protocol GWDriver <NSObject>
-(enum Status)getData;
-(void)cancel;
#end
I then have a class which lets call it DriverOne which I'm setting up like this
DriverOne.h
// DriverOne.h
#import <Foundation/Foundation.h>
#import "GWDriver.h"
#interface DriverOne : NSObject <GWDriver>
#end
DriverOne.m
// DriverOne.m
#import "DriverOne.h"
#implementation DriverOne
enum Status getData(char* encodedBuffer, int user)
{
// Copy C code which I showed in the link earlier
// into this method. I will want it to return a status
// and populate a global variable with the data.
}
void cancel()
{
// Cancels and closes driver
// is called from with in getData()
}
#end
I'm aware that the methods are currently written in C syntax here, I'm not sure if that is bad practice or not though at this point. Here is how I intend to call the method.
DriverOne *driver = [[DriverOne alloc] init];
driver.getData();
Am I completely off base here or is this approach correct in what I'm trying to achieve?
Thanks for any advice or suggestions.
Best practice dictates that you generally don't use C style functions in your Objective C classes.
char pointers are also frowned upon, generally. I would change your functions to something like this:
- (enum Status)getDataWithBuffer:(NSString *)buffer userId:(NSInteger)userId
{
char * encodedBuffer = [buffer UTF8String];
// Copy C code which I showed in the link earlier
// into this method. I will want it to return a status
// and populate a global variable with the data.
}
- (void)cancel
{
// Cancels and closes driver
// is called from with in getData()
}
and then change your call to this
DriverOne *driver = [[DriverOne alloc] init];
[driver getData:#"your data" userId:12345];
Is there an Objective-C runtime library function (unlikely) or set of functions capable of inspecting static (quasi-class level) variables in Objective-C? I know I can utilize a class accessor method but I'd like to be able to test without writing my code "for the test framework".
Or, is there a obscure plain C technique for external access to static vars? Note this information is for unit testing purposes—it needn't be suitable for production use. I'm conscious that this'd go against the intent of static vars... a colleague broached this topic and I'm always interested in digging into ObjC/C internals.
#interface Foo : NSObject
+ (void)doSomething;
#end
#implementation Foo
static BOOL bar;
+ (void)doSomething
{
//do something with bar
}
#end
Given the above can I use the runtime library or other C interface to inspect bar? Static variables are a C construct, perhaps there's specific zone of memory for static vars? I'm interested in other constructs that may simulate class variables in ObjC and can be tested as well.
No, not really, unless you are exposing that static variable via some class method or other. You could provide a + (BOOL)validateBar method which does whatever checking you require and then call that from your test framework.
Also that isn't an Objective-C variable, but rather a C variable, so I doubt there is anything in the Objective-C Runtime that can help.
The short answer is that accessing a static variable from another file isn't possible. This is exactly the same problem as trying to refer to a function-local variable from somewhere else; the name just isn't available. In C, there are three stages of "visibility" for objects*, which is referred to as "linkage": external (global), internal (restricted to a single "translation unit" -- loosely, a single file), and "no" (function-local). When you declare the variable as static, it's given internal linkage; no other file can access it by name. You have to make an accessor function of some kind to expose it.
The extended answer is that, since there is some ObjC runtime library trickery that we can do anyways to simulate class-level variables, we can make make somewhat generalized test-only code that you can conditionally compile. It's not particularly straightforward, though.
Before we even start, I will note that this still requires an individualized implementation of one method; there's no way around that because of the restrictions of linkage.
Step one, declare methods, one for set up and then a set for valueForKey:-like access:
// ClassVariablesExposer.h
#if UNIT_TESTING
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#define ASSOC_OBJ_BY_NAME(v) objc_setAssociatedObject(self, #v, v, OBJC_ASSOCIATION_ASSIGN)
// Store POD types by wrapping their address; then the getter can access the
// up-to-date value.
#define ASSOC_BOOL_BY_NAME(b) NSValue * val = [NSValue valueWithPointer:&b];\
objc_setAssociatedObject(self, #b, val, OBJC_ASSOCIATION_RETAIN)
#interface NSObject (ClassVariablesExposer)
+ (void)associateClassVariablesByName;
+ (id)classValueForName:(char *)name;
+ (BOOL)classBOOLForName:(char *)name;
#end
#endif /* UNIT_TESTING */
These methods semantically are more like a protocol than a category. The first method has to be overridden in every subclass because the variables you want to associate will of course be different, and because of the linkage problem. The actual call to objc_setAssociatedObject() where you refer to the variable must be in the file where the variable is declared.
Putting this method into a protocol, however, would require an extra header for your class, because although the implementation of the protocol method has to go in the main implementation file, ARC and your unit tests need to see the declaration that your class conforms to the protocol. Cumbersome. You can of course make this NSObject category conform to the protocol, but then you need a stub anyways to avoid an "incomplete implementation" warning. I did each of these things while developing this solution, and decided they were unnecessary.
The second set, the accessors, work very well as category methods because they just look like this:
// ClassVariablesExposer.m
#import "ClassVariablesExposer.h"
#if UNIT_TESTING
#implementation NSObject (ClassVariablesExposer)
+ (void)associateClassVariablesByName
{
// Stub to prevent warning about incomplete implementation.
}
+ (id)classValueForName:(char *)name
{
return objc_getAssociatedObject(self, name);
}
+ (BOOL)classBOOLForName:(char *)name
{
NSValue * v = [self classValueForName:name];
BOOL * vp = [v pointerValue];
return *vp;
}
#end
#endif /* UNIT_TESTING */
Completely general, though their successful use does depend on your employment of the macros from above.
Next, define your class, overriding that set up method to capture your class variables:
// Milliner.h
#import <Foundation/Foundation.h>
#interface Milliner : NSObject
// Just for demonstration that the BOOL storage works.
+ (void)flipWaterproof;
#end
// Milliner.m
#import "Milliner.h"
#if UNIT_TESTING
#import "ClassVariablesExposer.h"
#endif /* UNIT_TESTING */
#implementation Milliner
static NSString * featherType;
static BOOL waterproof;
+(void)initialize
{
featherType = #"chicken hawk";
waterproof = YES;
}
// Just for demonstration that the BOOL storage works.
+ (void)flipWaterproof
{
waterproof = !waterproof;
}
#if UNIT_TESTING
+ (void)associateClassVariablesByName
{
ASSOC_OBJ_BY_NAME(featherType);
ASSOC_BOOL_BY_NAME(waterproof);
}
#endif /* UNIT_TESTING */
#end
Make sure that your unit test file imports the header for the category. A simple demonstration of this functionality:
#import <Foundation/Foundation.h>
#import "Milliner.h"
#import "ClassVariablesExposer.h"
#define BOOLToNSString(b) (b) ? #"YES" : #"NO"
int main(int argc, const char * argv[])
{
#autoreleasepool {
[Milliner associateClassVariablesByName];
NSString * actualFeatherType = [Milliner classValueForName:"featherType"];
NSLog(#"Assert [[Milliner featherType] isEqualToString:#\"chicken hawk\"]: %#", BOOLToNSString([actualFeatherType isEqualToString:#"chicken hawk"]));
// Since we got a pointer to the BOOL, this does track its value.
NSLog(#"%#", BOOLToNSString([Milliner classBOOLForName:"waterproof"]));
[Milliner flipWaterproof];
NSLog(#"%#", BOOLToNSString([Milliner classBOOLForName:"waterproof"]));
}
return 0;
}
I've put the project up on GitHub: https://github.com/woolsweater/ExposingClassVariablesForTesting
One further caveat is that each POD type you want to be able to access will require its own method: classIntForName:, classCharForName:, etc.
Although this works and I always enjoy monkeying around with ObjC, I think it may simply be too clever by half; if you've only got one or two of these class variables, the simplest proposition is just to conditionally compile accessors for them (make an Xcode code snippet). My code here will probably only save you time and effort if you've got lots of variables in one class.
Still, maybe you can get some use out of it. I hope it was a fun read, at least.
*Meaning just "thing that is known to the linker" -- function, variable, structure, etc. -- not in the ObjC or C++ senses.
I want to use Protocol Buffers in an iOS project. I'm trying to avoid making the whole project into an Objective-C++ fiasco, so I want to wrap the C++ protobuf classes into Objective-C ones. I have several dozen protobuf messages, and while I have done this successfully one class at a time, ideally I would like to use inheritance to minimize the repeated code. I'm new to Objective-C and I haven't used what little I knew of C++ in 10 years, so this has mostly been an exercise in frustration. Below is an example of how I have wrapped a single message.
Code
.proto:
message MessageA {
optional string value = 1;
}
MessageAWrapper.h:
#import <Foundation/Foundation.h>
#interface MessageAWrapper : NSObject
#property (nonatomic) NSString *value;
+ (id)fromString:(NSString *)string;
- (NSString *)serialize;
#end
MessageAWrapper.mm:
#import "MessageA.h"
#import "message.pb.h"
#interface MessageAWrapper ()
#property (nonatomic) MessageA *message;
#end
#implementation MessageAWrapper
- (id)init
{
self = [super init];
if (self) {
self.message = new MessageA();
}
return self;
}
- (void)dealloc {
delete self.message;
self.message = NULL;
}
- (NSString *)value {
return [NSString stringWithUTF8String:self.message->value().c_str()];
}
- (void)setValue:(NSString *)value {
self.message->set_value([value UTF8String]);
}
- (NSString *)serialize {
std::string output;
self.message->SerializeToString(&output);
return [NSString stringWithUTF8String:output.c_str()];
}
+ (id)fromString:(NSString *)string {
MessageA *message = new MessageA();
message->ParseFromString([string UTF8String]);
MessageAWrapper *wrapper = [[MessageAWrapper alloc] init];
wrapper.message = message;
return wrapper;
}
#end
Goal
There is a lot of code here that will be repeated dozens of times in which the only variation is the wrapped class type (init, dealloc, serialize, fromString), so ideally I would like to put it on a parent ProtobufMesssage class instead. Unfortunately I've had no success in making this work because I can't find a way for the parent class to know the class its children are using, which is required for example in init and fromString.
Things I've attempted
struct
template class
void*
Obstacles I've encountered
can't find a way to store a reference to a class/type
can't have any C++ headers or code in the .h file (as this requires the whole project to be Objective-C++)
difficulty keeping references to the protobuf message parents (Message or MessageLite) because they are abstract
As I said I have very little understanding of C++ or Objective-C; most of my experience is with much higher level languages like Python and Java (though I do mostly understand basic C things like pointers).
Is this perhaps not even possible? Am I approaching it wrong or missing something obvious? Any help would be much appreciated. Thanks.
I don't know much about C++ at all, but can't you declare the Objective-C property to be a Message *?
You've already separated the C++ code from the header by declaring the property in the .mm file, the problem you will have is with instance methods named by the compiler (value() and set_value()) and only being valid methods for the subclass. It might help to use the Reflection class to get and set fields by their name. Here is an excerpt from Google's message.h showing this:
Message* foo = new Foo;
const Descriptor* descriptor = foo->GetDescriptor();
const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
assert(text_field != NULL);
assert(text_field->type() == FieldDescriptor::TYPE_STRING);
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);
const Reflection* reflection = foo->GetReflection();
assert(reflection->GetString(foo, text_field) == "Hello World!");
You could create Objective-C -objectForKey: and -setObject:forKey: instance methods that typecheck and get or set the value (confusingly, the key in the case of MessageAWrapper would be #"value"). Your subclasses would not even need to be aware of the C++ code.
You can also separate the creator function in -init and +fromString: method into something like, +_createNewInstance;
+(Message*)_createNewInstance{ return new MessageA(); }
allowing your subclasses of MessageWrapper to reuse all code except for creating the C++ object.
While Objective C has very powerful instrospection capabilities, C++ is more limited. You do have RTTI (Run time type information), but it's not even as powerful as the Objective C counterpart.
However, it might be enough for you. Within your Objective C++ class, you might find the type of you message object with the typeid operator:
if( (typeid(self.message) == typed(foo)){
//doSomething
else if( (typeid(self.message) == typed(bar)){
// doSomething else
}
Maybe the best option is to add another indirection level. Make an Objective C class hierarchy that wraps all your protocol buffer C++ classes and then create another Objective C that uses those classes (as delegates maybe). I believe this might be a better option. Use C++ only for those unavoidable cases.
Good luck!
I'd like to write an Objective-C class without Cocoa or GNU's Object.h (for educational purposes). I dug around the net and it seems to me that quite a lot of stuff that one would expect to "come with the language", such as classes and message sending are actually defined in files written by third parties, such as objc-runtime.h.
Is there any documentation about what is really pure Objective-C and what is part of the runtime / frameworks? And what functionality do I have to implement to get a working environment without using any third-party code such as Object.h or objc-runtime.h (note again that this is for educational purposes, not for production code)?
Thanks for any insight!
Really, the only thing you must take care of yourself if you don't inherit from NSObject is object creation and destruction; methods otherwise behave the same way regardless of their parent class. Features like KVC and memory management are features of OpenStep/Cocoa, but not required as part of the language.
Here's a class from scratch:
#interface MyClass { // note the lack of a superclass here
#private Class isa;
}
+ (MyClass *)create;
- (void)destroy;
- (int)randomNumber;
#end
#implementation MyClass
+ (MyClass *)create {
return class_createInstance(self, 0);
}
- (void)destroy {
object_dispose(self);
}
- (int)randomNumber {
return rand();
}
#end
And here's how it could be used:
int main(int argc, char **argv) {
MyClass *foo = [MyClass create];
if (foo) {
printf("random! %i\n", [foo randomNumber]);
[foo destroy];
}
}
Edit: If you don't even want to use class_createInstance() and object_dispose(), you'll have to implement equivalents manually, as well as an equivalent of class_getInstanceSize() so you know how much memory an object occupies. But even if you manage that, don't think you've escaped the Objective-C runtime! Message dispatch is still entirely built on the C functions in the runtime, and Objective-C syntax is transformed into calls to those functions during compilation.
Matt Gallagher wrote a really cool post on writing a bare-bones Cocoa program. Since Objective-C is a superset of C, you can just do:
echo "int main(){return 0;}" | gcc -x objective-c -; ./a.out ; echo $?
Anyways, you probably would get a lot out of reading his post.
As far as avoiding the framework and creating your own base object goes, all you need to do is make sure that the first iVar is declared Class is_a and you could probably have a reasonable stab at replicating NSObject is by passing through to the runtime functions.
As far as avoiding the runtime library AND the framework goes, that's not really possible. Objective C (or at least, the bits that aren't just C) is a dynamic language. So pretty much everything it does that C doesn't do is handled by the runtime library.
It might be possible to build your own classes and objects using the 32bit runtime and the deprecated API, which doesn't abstract away the layout of classes, protocols, etc. to the extent that the modern runtime does (I've only really poked around with the modern runtime)
Perhaps you could create classes, add methods and allocate instances and by setting values in class_t structs and then using malloc() to allocate, although even then, you'd still be implicitly using the runtime function objc_msgSend every time you used the [obj selector] syntax -- unless you want to implement that as well, in which case you've just reimplemented the language yourself. The 'pure core' of the language you're looking for just is the runtime.
Here's an example of class, without using class_createInstance or object_dispose, or any other Objective-C Runtime (at least we don't call them directly).
#import <objc/objc.h>
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
static Class __scratchClass = NULL;
#interface Scratch {
Class isa;
char *name;
}
+ (id) initialize;
+ (Scratch*) new:(const char*)strName;
- (void) sayHello;
- (void) destroy;
#end
#implementation Scratch
+ (id) initialize {
__scratchClass = self;
return self;
}
+ (Scratch*) new:(const char*) strName {
Scratch* pObj = (Scratch*)malloc(sizeof(Scratch));
if (!pObj) return NULL;
memset(pObj, 0, sizeof(Scratch));
pObj->isa = __scratchClass;
pObj->name = (char*)malloc(strlen(strName)+1);
strcpy(pObj->name, strName);
return pObj;
}
- (void) sayHello {
printf("Hello, World!\nThis is Scratch (%s)...\n", name);
}
- (void) destroy {
if (name) {
free(name);
name = NULL;
}
free(self);
}
#end
int main(int argc, char** argv) {
Scratch* ps = [Scratch new:argv[0]];
[ps sayHello];
[ps destroy];
return 0;
}
Compile the code with (assuming you save it as 'test1.m'):
gcc -o test1 test1.m -lobjc
I've read many things about enum types in objective-c, and I see there is many ways to define them. But I don't see the right way (if there is one) to define an enum that can be called with CARS.ROLLSROYCE and that cannot be used only with ROLLSROYCE in the code.
So I can define ROLLSROYCE in the CARS enum and also in the BEAUTIFULCARS enum.
Do you know the way to define such an enum ?
You are trying to implement namespaces for your Enums in Objective-C. What you're asking for is a lot of elbow grease in Objective-C. You are probably best-off using C++ for this, since it is easy and afaik fully supported in any iOS or Cocoa application. You'll have to rename the files that #import your C++ code to .mm files instead of .m files, and the C++ compiler can be trickier than the Objective-C one. Going this route you'll create a header file like Enums.h.
// Enums.h
namespace CARS
{
enum CARS
{
ROLLSROYCE
};
}
namespace BEAUTIFULCARS
{
enum BEAUTIFULCARS
{
ROLLSROYCE = 45
};
}
And in your .mm sourcefile
#import "Enums.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS::ROLLSROYCE,
BEAUTIFULCARS::ROLLSROYCE);
}
If you want to avoid using C++ for this solution, there's a lot more elbow grease, bookkeeping, and opportunity for error. You'll need a header and a source file for this.
// CARS.h
#interface BEAUTIFULCARS : NSObject
{
enum
{
BEAUTIFULCARS_ROLLSROYCE = 45
} BEAUTIFULCARS;
}
#end
#interface CARS : NSObject
{
enum
{
CARS_ROLLSROYCE
} CARS;
}
#end
// CARS.m
#implementation BEAUTIFULCARS
+(NSInteger)ROLLSROYCE{ return BEAUTIFULCARS_ROLLSROYCE; }
#end
#implementation CARS
+(NSInteger)ROLLSROYCE{ return CARS_ROLLSROYCE; }
#end
Your .m source is almost the same:
#import "CARS.h"
-(void)printEnumvals
{
NSLog(#"CARS %d BEAUTIFULCARS %d",
CARS.ROLLSROYCE,
BEAUTIFULCARS.ROLLSROYCE);
}
Objective-C does not manage scope in the same way that most other OO languages do. Interfaces define the properties and messages that an object that interface supports, but don't support protection levels like public or private. When you define an enum in an #interface, that enum ends up in global scope.
For my case, I didn't want to use C++ namespaces or write redundant Objective-C classes for such a simple case, so I fallen back to the C.
// Enum.h
typedef struct
{
const int ROLLSROYCE;
} _CARS;
typedef struct
{
const int ROLLSROYCE;
} _BEAUTIFULCARS;
extern const _CARS CARS;
extern const _BEAUTIFULCARS BEAUTIFULCARS;
And then in Enum.m, define values
// Enum.m
#import "Enum.h"
const _CARS CARS = {0};// 0 is to be assigned to ROLLSROYCE field in struct
const _BEAUTIFULCARS BEAUTIFULCARS = {1}; // same but with 1
And finally, in your "main" code
#import "Enum.h"
// Some method
{
NSLog(#"I can refer to CARS.ROLLSROYCE = %d and BEAUTIFULCARS.ROLLSROYCE = %d", CARS.ROLLSROYCE, BEAUTIFULCARS.ROLLSROYCE);
}
Which will produce this output:
I can refer to CARS.ROLLSROYCE = 0 and BEAUTIFULCARS.ROLLSROYCE = 1