I have some problems with Protocols in Categories with clang compilier in Objective-C.
I think clang ignore any protocols if this specified in Category, like in sample code below.
If line "#interface MyClass() <MyProtocol>" is replaced to "#interface MyClass()" than object files is absolutely same (byte-to-byte).
#include <stdio.h>
#include <Foundation/Foundation.h>
#protocol Protocol1
#end
#protocol MyProtocol
#end
#interface MyClass : NSObject<Protocol1>
#end
#interface MyClass() <MyProtocol>
#end
#implementation MyClass
#end
int main() {
if ([MyClass conformsToProtocol:#protocol(Protocol1)])
printf("Protocol1 is conformed\n");
if ([MyClass conformsToProtocol:#protocol(MyProtocol)])
printf("MyProtocol is conformed\n");
return 0;
}
I compilied this code on my Ubuntu and I got next output:
$ clang-3.5 -o main main.m -I `gnustep-config --variable=GNUSTEP_SYSTEM_HEADERS` -L `gnustep-config --variable=GNUSTEP_SYSTEM_LIBRARIES` -lgnustep-base -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS -lobjc
$ ./main
Protocol1 is conformed
But if this code is buid on OS X, I will get next ouput:
$ clang -o main main.m -lobjc
$ ./main
Protocol1 is conformed
MyProtocol is conformed
This problem is related with options -fobjc-runtime=gnustep and -fobjc-runtime=macosx, but I don't know why.
How can I fix this problem with gnustep environment? What can I do?
Related
oc project;
I has class like this
#interface MyObject : NSObject
#property(noatomic,getter=getNode)id node;
#end
and in swift file
var node = MyObject().getNode
and getNode method not found ?
anyone helps
Preface: I have little experience with C integration in iOS, feel free to correct me on any misinterpretations I have about this.
I have a project that has a custom 2-tier "SDK" both written in C. The coreSDK makes method calls to the deviceSDK which communicates with the ios framework to execute hardware actions (ie. enable camera) or retrieve device information (ie. path to NSDocumentDirectory).
Unfortunately, due to the infrastructure, both SDK file extensions use (.h) and (.c) and cannot be changed to (.m) as some sources recommended. According to what I've read, I can create C-callbacks to the ObjC methods but that's only really viable for singletons, and the C-callback needs to be within the scope of the (.m) file.
I have tried creating a wrapper class in ObjC such that it has a C-callback from which the deviceSDK calls to, but when including the header(.h) for that (.m), the compiler seems to crash. If my understanding is correct, it's because the C-compiler cannot interpret the ObjC language contained in the (.m).
I believe theoretically is possible to write iOS apps in pure C with ObjC runtime, but ideally would rather not go down that route as what I've seen is absurdly complicated.
An example workflow
ViewController.m method calls to coreSDK method (.c)
coreSDK method calls to deviceSDK method (.c)
deviceSDK needs to retrieve (for example) NSDocumentDirectory (or enable camera)
How can I achieve this?
Code examples would be most comprehensive and appreciated.
Thanks!
These are some(not all) references I've already looked into...
How to write ios app purely in c
Pure C function calling Objective-C method
C function calling objective C functions
Using native objective-c method for C callbacks
Callback methods from C to Objective-C
Mixing C functions in an Objective-C class
How to call an Objective-C method from a C method
How to use pure C files in an objective-C project
Edit: 2016-07-21
To clarify the issue, I'm having trouble making calls from C methods in (.c) files to ObjC methods in (.m) files, or figuring out an alternative means to retrieve information such as (for example) NSDocumentsDirectory in ObjC (.m files) and passing back to C in (.c) files.
Example Code: Of course it's incorrect but it's along the lines of my expectations or what I'm hoping to achieve.
//GPS.h
#include "GPSWrapper.h"
STATUS_Code GPSInitialize(void);
//GPS.c
#include "GPS.h"
STATUS_Code GPSInitialize(void) {
GPS_cCallback();
}
//GPSWrapper.h
#import <Foundation/Foundation.h>
#interface GPSWrapper: NSObject
- (void) testObjC;
#end
//GPSWrapper.m
#import "GPSWrapper.h"
static id refToSelf = nil;
#implementation GPSWrapper
- (void) testObjC {
// just an example of a ObjC method call
NSString *documentsDirectory = [paths objectAtIndex:0];
NSLog(documentsDirectory);
}
#end
static void GPS_cCallback() {
[refToSelf testObjC];
}
This line #include "GPSWrapper.h" in your example is the problem. You can't include a header that has ObjC syntax in a file that's being compiled as C. Any interface to the ObjC side that's being included in your C code needs to be broken out into its own header that contains only valid C. Here's a demo of what you need:
First, header and implementation file for the C-only stuff.
// CUtils.h
// OCFromC
#ifndef CUtils_h
#define CUtils_h
#include <stdio.h>
void doThatThingYouDo();
void doThatThingWithThisObject(const void * objRef);
#endif /* CUtils_h */
// CUtils.c
// OCFromC
// Proof that this is being compiled without ObjC
#ifdef __OBJC__
#error "Compile this as C, please."
#endif
#include "CUtils.h"
#include "StringCounterCInterface.h"
void doThatThingYouDo()
{
printf("%zu\n", numBytesInUTF32("Calliope"));
}
void doThatThingWithThisObject(const void * objRef)
{
size_t len = numBytesInUTF32WithRef(objRef, "Calliope");
printf("%zu\n", len);
}
Note that second function; if you need to, you can pass around an object reference in C land, as long as it's cloaked in a void *. There's also some casting that needs to be done for memory management. More on that below.
This is the exciting ObjC class we'll be using:
// StringCounter.h
// OCFromC
#import <Foundation/Foundation.h>
#interface StringCounter : NSObject
- (size_t)lengthOfBytesInUTF32:(const char *)s;
#end
// StringCounter.m
// OCFromC
#import "StringCounter.h"
#implementation StringCounter
- (size_t)lengthOfBytesInUTF32:(const char *)s
{
NSString * string = [NSString stringWithUTF8String:s];
return [string lengthOfBytesUsingEncoding:NSUTF32StringEncoding];
}
#end
Now, this is the important part. This is a header file that declares C functions. The header itself contains no ObjC, so it can be included in CUtils.c as you saw above.
// StringCounterCInterface.h
// OCFromC
#ifndef StringCounterCInterface_h
#define StringCounterCInterface_h
// Get size_t definition
#import <stddef.h>
size_t numBytesInUTF32(const char * s);
size_t numBytesInUTF32WithRef(const void * scRef, const char *s);
#endif /* StringCounterCInterface_h */
This is the connection point. Its implementation file is compiled as ObjC, and it contains the definitions of those functions just declared. This file imports the interface of StringCounter, and so the functions can use methods from that class:
// StringCounterCInterface.m
// OCFromC
#ifndef __OBJC__
#error "Must compile as ObjC"
#endif
#import "StringCounterCInterface.h"
#import "StringCounter.h"
size_t numBytesInUTF32(const char * s)
{
StringCounter * sc = [StringCounter new];
// Or, use some "default" object in static storage here
return [sc lengthOfBytesInUTF32:s];
}
size_t numBytesInUTF32WithRef(const void * objRef, const char * s)
{
StringCounter * sc = (__bridge_transfer StringCounter *)objRef;
return [sc lengthOfBytesInUTF32:s];
}
Now, in main or wherever you like you can exercise those functions from CUtils:
// main.m
// OCFromC
#import <Foundation/Foundation.h>
#import "StringCounter.h"
#import "CUtils.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
doThatThing();
// Create an object reference
StringCounter * sc = [StringCounter new];
// Tell ARC that I know this is dangerous, trust me,
// pass this reference along.
const void * scRef = (__bridge_retained void *)sc;
doThatThingWithThisObject(scRef);
}
return 0;
}
The bridging cast, along with its counterpart in StringCounterCInterface.m, lets you move an ObjC object through areas where ARC cannot go. It bumps the object's retain count before it is hidden in the void *, so that it will not be accidentally deallocated before you can __bridge_transfer it back to ObjC land.
One final note: If you are going to be passing object references around in C a lot, you might consider doing typedef void * StringCounterRef; and changing the signatures of everything appropriately.
I develop an app that using CommonCrypto library. The problem is I can create an instance in Swift file. My object created using Objective- C. It seems can't create bridging header very well.
Error message
/Users/MNurdin/Documents/iOS/xxxxx/Models/Main.swift:15:9: 'CustomObject' does not have a member named 'encrypt'
CustomObject.h
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>
#import "GTMBase64.h"
#interface CustomObject : NSObject
+ (NSString*)encrypt:(NSString*)plainText withKey:(NSString*)key;
#end
CustomObject.m
#import "CustomObject.h"
#implementation CustomObject
+ (NSString*)encrypt:(NSString*)plainText withKey:(NSString*)key{
/*--*/
return result;
}
#end
Global.swift
var instanceOfCustomObject: CustomObject = CustomObject()
println(instanceOfCustomObject.encrypt("p#$$w0rd","12345678"))
The initial + in the declaration indicates that
+ (NSString*)encrypt:(NSString*)plainText withKey:(NSString*)key;
is a class method in Objective-C. You have to call it on the
class (or type in Swift linguage) itself, not on an instance:
let encrypted = CustomObject.encrypt("p#$$w0rd", withKey: "12345678")
Can't understand the error.
duplicate symbol _currentCount in:
/Users/selim/Library/Developer/Xcode/DerivedData/iXEN-aimjepotqgbjmlaghqjovwpsngvx/Build/Intermediates/iXEN.build/Debug-iphonesimulator/iXEN.build/Objects-normal/i386/Server.o
/Users/selim/Library/Developer/Xcode/DerivedData/iXEN-aimjepotqgbjmlaghqjovwpsngvx/Build/Intermediates/iXEN.build/Debug-iphonesimulator/iXEN.build/Objects-normal/i386/Alerts.o
ld: 1 duplicate symbol for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
1、if you declare the currentCount in .h file and include it in two .m file.
Add extern in front of currentCount declaration in .h file.
example
extern int currentCount;
2、if you declare the currentCount in two .m file.
And static in front of currentCount in .m file
example
static int currentCount
One more thing, variable declare after #implementation doesn't belong to that class , it is global value.
#interface Obj : NSObject
#end
#implementation Obj
int a = 0 ; // a declare in Obj class
#end
#interface Obj2 : NSObject
#end
#implementation Obj2
- (id)init
{
self = [super init] ;
if (self) {
a = 1 ; // you can access it in Obj2 class
}
return self ;
}
#end
Add Quartzcore framework
or check the file you don't have any duplicate file name in project.i think you add two projects thats why this error is occur.
Check it may you write a "#import file.m" instead of "#import file.h". So, In Compiles Resource will duplicate symbol file.o.
You may need to remove the duplicates in Targets Build Phases under the Compiled Sources grouping.
Example .h file:
#interface MyClass : NSObject
typedef NS_ENUM(int, myType) {
Something,
SomethingElse,
SomethingElseElse,
YetAnotherSomethingElse
};
{ //Error On This Line: Expected Identifier or '('
int aInstanceVariable;
}
//Some Methods go here
#end
Why am I getting that error (see the comment in the code above)? It works fine when below the class instance variable declaration, but I would like to use it as the type for one of my instance variables.
Thanks to #CarlVeazey, I discovered that the answer was simple: Move the typedef declaration to above #interface. The reason for this is that types cannot be owned by a class or an instance of a class, and therefore cannot be in the interface for a class.