Let's say we have following C++ code:
struct ISomeInterface
{
virtual ~ISomeInterface() {}
virtual void f() = 0;
};
class SomeClass : public ISomeInterface
{
public:
void f() override
{
std::cout << "Hi";
}
};
void getObject(ISomeInterface*& ptr)
{
ptr = new SomeClass;
}
int main()
{
ISomeInterface* p(nullptr);
getObject(p);
p->f();
delete p;
}
It's quite straightforward and far from being perfect, but it draws the picture: getting a pointer to an interface to an object via function's parameters.
How do we get the same with Objective C protocols?
#protocol SomeProtocol <NSObject>
- (void)f;
#end
#interface SomeClass : NSObject<SomeProtocol>
- (void)f;
#end
#implementation SomeClass
- (void)f { NSLog(#"Hi"); }
#end
Thanks in advance.
If you actually want the reference parameter, you can do:
void getObject(id<SomeProtocol> *ptr)
{
if (ptr) {
*ptr = [[SomeClass alloc] init];
}
}
int main(int argc, char *argv[])
{
#autoreleasepool {
id<SomeProtocol> p = nil;
getObject(&p);
[p f];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
C-style function:
id<SomeProtocol> getObject()
{
return [SomeClass new];
}
Objective-C (class) function:
#implementation SomeOtherClass
+ id<SomeProtocol> getObject
{
return [SomeClass new];
}
#end
Related
Is this the correct method to prevent more than one thread to access the function MyTaskF?
.h file:
#interface MyInterface : NSObject {
//... some other stuff here
}
.m file:
static NSLock *mytaskMutex;
static MyInterface *MyInterfaceSingleton;
int MyTaskF(int iVar)
{
[mytaskMutex lock];
//do stuff in here
[mytaskMutex unlock];
return 0;
}
Consider this code example:
class SomeArbitrarilyNamedClassPlusPlus {
public:
SomeArbitrarilyNamedClassPlusPlus(NSObject *object) { object_ = object; }
SomeArbitrarilyNamedClassPlusPlus() { object_ = nil; }
private:
NSObject *object_;
};
#interface SomeArbitrarilyNamedClassObjective : NSObject
{
SomeArbitrarilyNamedClassPlusPlus *_plusPlusObject;
}
#end
#implementation SomeArbitrarilyNamedClassObjective
-(id)init
{
if ((self = [super init]))
{
_plusPlusObject = new SomeArbitrarilyNamedClassPlusPlus(self);
}
return self;
}
-(void)dealloc
{
NSLog(#"deallocated");
delete _plusPlusObject;
}
#end
int main(int argc, const char * argv[])
{
{
SomeArbitrarilyNamedClassObjective *object = [[SomeArbitrarilyNamedClassObjective alloc] init];
}
return 0;
}
The object variable never gets deallocated. You can check it with Instruments - additional retain counter increment happens inside the -(id)init call.
I would never expect that attributes in C++ classes are strong and this makes me wondering - is there a way to make c++ attributes pointing on Objective-C objects weak?
UPDATE:
There is a way to avoid this using pointers to void in C++ class instead of NSObject* and initialize C++ class in -(id)init method like that:
...
_plusPlusObject = new SomeArbitrarilyNamedClassPlusPlus((__bridge void*)self);
...
However, the question still remains - is there a way to save Objective-C types inside C++ classes but make them weak?
Well, the answer turned out to be quite straightforward - use __weak attribute in C++ class:
class SomeArbitrarilyNamedClassPlusPlus {
public:
SomeArbitrarilyNamedClassPlusPlus(NSObject* object) { object_ = object; }
SomeArbitrarilyNamedClassPlusPlus() { object_ = nil; }
private:
__weak NSObject* object_;
};
best to explain with an example:
in my AudioItem.h
#define ITEM_CAPACITY 100
typedef struct DataStruct {
void * content;
UInt32 size;
} DataStruct;
typedef DataStruct *DataStructRef;
#interface AudioItem : NSObject
{
DataStructRef data;
}
#property (assign, readwrite) DataStructRef data;
in AudioItem.m
#synthesize data;
-(id)initWithID:(NSString *)itemID
{
self = [super init];
data->content = malloc(ITEM_CAPACITY);
return self;
}
The above code looks a lot like this one, but I get a BAD_EXEC_ERROR.. how come? The reason why I would like to use a C buffer rather than some NSMutableData or whatever is b/c I've tried using NSMutableData and I feel like it's slowing down my real time application
it fails because data is a null pointer when you set its content.
the easy way to do this is:
enum { ITEM_CAPACITY = 100 };
typedef struct DataStruct {
char content[ITEM_CAPACITY];
UInt32 size;
} DataStruct;
#interface AudioItem : NSObject
{
#private
DataStruct data;
}
#implementation AudioItem
- (id)initWithID:(NSString *)itemID
{
self = [super init];
if (0 == self) return;
data.size = ITEM_CAPACITY;
return self;
}
In Objective-C, it is possible to pass a class as a parameter to a method:
- (void) methodThatTakesClass:(Class)theClass;
And it is possible to pass an instance that is conforming to a protocol as a parameter:
- (void) myConformInstance:(id <MyProtocol>)theObject;
Is it possible to use the combined functionality? A method which takes a class which is conforming to a certain protocol.
Yes. The following is a valid program which will log the NSObject class.
#import <Foundation/Foundation.h>
void f(Class <NSObject> c) {
NSLog(#"%#",c);
}
int main() {
f([NSObject class]);
}
This would cause a compiler error if you tried to pass a class which doesn't conform to NSObject, such as the Object class. You can also use it for methods.
- (void)printClass:(Class <NSObject>)c;
also valid:
#interface Something: Object {
}
- (void) foo:(int(*)(void))bar;
#end
#implementation Something
- (void) foo:(int(*)(void))bar {
return (*bar)();
}
#end
int someFunc( void ) {
return 9;
}
int main ( int argc, char **argv ) {
Something *object = [[Something alloc] init];
printf( "%i\n", [object foo:&someFunc] );
[object release];
return 0;
}
c++ code
--------
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
public:
static int a;
void set(int s)
{
a=s;
cout<<a<<endl;
}
void setData(int f)
{
cout<<"I am "<<f<<" years old!!!"<<endl;
}
};
int A::a=0;
int main()
{
A* ab=new A();
ab->set(10);
ab->setData(ab->a);
return 0;
}
I am trying to get the same output for
this equivalent Objective C code.
main.m
---------
#import <Foundation/Foundation.h>
#import "A.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
A* ab = [[A alloc]init];
[ab set:10];
[ab setData:ab.a]; //getting error when passed ab->a or ab.a as an argument
[pool drain];
return 0;
}
A.h
---
#import <Foundation/Foundation.h>
#interface A : NSObject {
}
-(void)set:(int)s;
-(void)setData:(int)f;
#end
A.m
----
#import "A.h"
#implementation A
static int a;
-(void)set:(int)s
{
a=s;
NSLog(#"%d\n",a);
}
-(void)setData:(int)f
{
NSLog(#"%d",f);
}
#end
Error:Request for member 'a' in something not a structure or union.
There are no static instance variables or methods in Objective C. What you want can be done with class methods and static file scope variables. Class methods are those methods sent to class objects rather than instances.
#interface AClass
{
}
+(int) a;
+(void) setA: (int) newValue;
#end
// A.m
static int aStorage = 0;
#implementation AClass
+(int) a
{
return aStorage;
}
+(void) setA: (int) newValue
{
aStorage = newValue;
}
#end
// To use:
int something = [AClass a];
[AClass setA: something * 2];
// Or dot syntax if you prefer
AClass.a = AClass.a * 2;
First, declaring a static int in your implementation file doesn't magically make it a member of class A; your ObjC class A has no member variables.
Second, ab->a isn't how you would access the member of a class in ObjC. Once you have a member, write a getter for a, and use a method call to access it. (Or if you really want it to be static, don't add a member, and just add a getter that returns the static variable.)