Use std::string as datamember in objective-c - objective-c

I want to use a C++ string object in my Objective-C code instead of a NSString so I don't need to covert it (I need the std::string more often) and I tried doing it like this:
using namespace std;
#interface InstrumentGridViewController : UIViewController {
string* trackName; // also tried using std::string, didn't work
#property (nonatomic, assign) string* trackName;
}
I'm getting errors though, both the string* trackName; statement and the #property line give me Expected specifier-qualifier-list 'string'.
EDIT: I forgot to add #include <string> but adding this gives me the error String: no such file or directory

What matters is the source files this header file is included by. If this header file is included in a normal Objective-C source file (.m extension) the compiler will choke as you described. If you check the errors carefully in Xcode you can see exactly which source file or files this header file failed to compile in.
This is why it is often suggested never to use C++ objects in header files intended to be consumed by Objective C code. C++ in header files tends to bleed all over your code base and force you to compile everything was Objective C++ (.mm extension). Note that with the modern runtime and class extensions it is very easy to work around this. Just move your:
#property (nonatomic, assign) string* trackName;
to a class extension in your InstrumentGridViewController.mm file and remove the trackName ivar declaration that is not needed in the modern runtime. Then your header is Objective C clean and can be included by the rest of your code. Rob Napier has more discussion on this in Wrapping C++ Final Edition.

If you want to compile everything as Obj-c++ and don't want to go through the tiresome process of changing all your file extensions, just provide the -x objective-c++ flag to the compiler (project settings -> other c flags) and link with the stdlibc++. That way you can use c++ all other your code without worrying

Related

Generic classes in "frameworkname"-Swift.h causes "Type name requires a specifier or qualifier" error in Xcode 6.3

I updated to Xcode 6.3, and I had two separate projects (one is a framework) in my workspace. Now, Xcode autogenerated this "frameworkname"-Swift.h header file, but when I had a generic class as a property, it produces the following lines:
#class Presentation;
SWIFT_CLASS("_TtC13BusinessLogic31MeetupDetailViewControllerModel")
#interface MeetupDetailViewControllerModel : NSObject
#property (nonatomic) /* RsvpStore<Rsvp> */ anRsvpStore;
#end
There is no equialent to gerenics in Objective-c, so how can I solve this problem?
I found that I can solve the problem if I set the type to NSObject like:
#property (nonatomic) NSObject * __nonnull anRsvpStore;
but with every build, this file is recreated to the same wrong version. So how can I force this build to set the type of this generic to NSObject?
I could stop creating this compatibility header by setting in Build Settings -> Swift Compiler - Code Generation -> Intall Objective-C Compatibility Header to No.
Since I've not written Objective-C code in my project, there is no problem with this option, but this is rather a workaround than a solution for generics in the compatibility header.
Another workaround is if you mark your properties with private, then they won't appear in the compatibility header.
Swift 2.0 update
A new
#nonobjc
attribute is introduced to selectively suppress ObjC export for instance members that would
otherwise be
#objc
. (16763754)
Blockquote
Not tested, but this looks like a solution.
I solved in #1873 https://github.com/realm/realm-cocoa/issues/1873
If you don't need to use swift in objc,just set Intall Objective-C Compatibility Header to No.
If you need to use swift in objc,you have to edited the -Swift.h and set it in Objective-C Generated Interface Header Name

options to forward declare a C typedef in obj-c #interface

My obj-c class uses a C library (the Chipmunk physics engine), which has an Obj-C wrapper interface.
I want to add a property with a chipmunk type (cpLayers) to my object, like so:
#interface
#property cpLayers layers;
...
The easiest way is to #import "ObjectiveChipmunk.h", but that seems ridiculous to import all of the headers just to get one measly type.
If I #import the C "chipmunk_types.h" file where cpLayers is defined "typedef unsigned int cpLayers;", I get compiler errors related to ARC. They are bridge/casting errors in a macro that is defined in chipmunk_types.h and used in my .m file.
If I add just the definition, or #include chipmunk_types.h, I get redefinition errors.
Is there any better way to do this? And WHY the ARC errors?
Take a look at the ObjectiveChipmunk.h, that is where it overrides the basic Chipmunk types using preprocessor defines. You can add those defines as compiler flags if you want to work around the problem, but I wouldn't really worry about it. You are already doing Objective-C programming after all, have you ever looked at the gargantuan amount of includes that get pulled in when you import something as innocuous as Foundation.h? Importing the full ObjectiveChipmunk.h header is like 1% in comparison.

Xcode and ZXingWidget: Importing Obj-C header files within .mm files

I use XCode 4.0 for developing an iOS project.
In my current project, I added the ZXingWidget library correctly but I had to change the .m extension in .mm in the class which implements MyViewController in order to import "QRCodeReader.h" and "ZXingWidgetController.h", the two headers I need to use the ZXing library.
Now, if in the same MyViewController.mm I want to also import my AppDelegate (which is obviously an Objective-C class), I receive a compile error which Xcode signals into other header files that are recursively added by my AppDelegate. These errors are of these kinds:
GCC 4.2 Error - Instance variable '<unnamed'> has unknown size
Expected ';' before 'public'
Expected unqualified-id before 'public'
I believe this is because I don't manage correctly the Objective-C and C++ mixing, and as I comment the line #import "MyAppDelegate.h" the error disappears.
Is there something I can do to fix this problem? Also a workaround could do!
Thanks!
Edit 1: The error does occur only if I import the App Delegate header in that .mm file. In every other .m file of my project I can successfully import the same App Delegate without errors. I feel there's something wrong with the .mm extension and GCC.
SOLVED: I had another external library interface which used this code
#interface Name : NSObject {
#private
#public
id var1;
int var2; // ecc...
}
And the error was pointing to the keyword #public. I commented the #private keyword and everything went just fine! I would be happy if someone could explain me the reason of this.

How to use c++ template class in objective C

I want to use a Template class of C++ in my Objective C project.
I have read that it is supported.
When I try to import the template class that is written in C++ I get lot of errors like
Cannot find protocol declaration for 'class'
etc..
Can anyone give me a simple example of this.
Waiting for reply.
You are putting the objective c++ code in a .mm file? You need to use .mm files to tell the compiler its allows to parse c++ constructs in addition to objective-c and c.
You can't just change the name of a header file from .h to .mm - the name of the file containing the #include / #import directive needs to change.
// file: main.m
#import "cppclassdef.h" //will not work
#import "cppclassdef.mm" // also will not work. additionally will confuse XCode which will try to compile the .mm file by itself.
// file: main.mm
#import "cppclassdef.h" // this is how to do it.

Forward-declare enum in Objective-C

I'm having trouble with enum visibility in an Objective-C program. I have two header files, and one defines a typedef enum. Another file needs to use the typedef'd type.
In straight C, I would simply #include the other header file, but in Objective-C, it's recommended not to use #import between header files, instead using forward #class declarations as needed. However, I can't figure out how to forward-declare an enumeration type.
I don't need the actual enumerated values, except in the corresponding .m implementation file, where I can safely #import away. So how can I get the typedef enum to be recognized in the header?
Most recent way (Swift 3; May 2017) to forward declare the enum (NS_ENUM/NS_OPTION) in objective-c is to use the following:
// Forward declaration for XYZCharacterType in other header say XYZCharacter.h
typedef NS_ENUM(NSUInteger, XYZCharacterType);
// Enum declaration header: "XYZEnumType.h"
#ifndef XYZCharacterType_h
#define XYZCharacterType_h
typedef NS_ENUM(NSUInteger, XYZEnumType) {
XYZCharacterTypeNotSet,
XYZCharacterTypeAgent,
XYZCharacterTypeKiller,
};
#endif /* XYZCharacterType_h */`
The answer to your question is to either go ahead and import the typedef header file or to use a generic type like NSInteger instead of the enum type.
However, there is more reason to not importing a header file than just compile speed.
Not importing a header file also reduces your inadvertent access to extraneous classes.
For example, say you have a TrackFileChanges class that tracks the file system for changes to a specific file, and you have a CachedFile class that stores cached data from a file. The latter might use a private ivar of type TrackFileChanges*, but for uses of CachedFile, this is simply an implementation detail (ideally, the ivar would be auto-generated with a private property using the new runtime, but thats not possible if you're using the old run time).
So clients that #import "CachedFile.h" probably do not need or want access to TrackFileChanges.h. And if they do, they should make it clear by #importing it themselves. By using #class TrackFileChanges instea of #import "TrackFileChanges.h" in CachedFile.h you improve the encapsulation.
But all that said, there is nothing awrong with importing a header file from a second header file if the second header wants to expose the first to all clients. For example, header files that declare classes need to be imported directly in subclassing header files, and header files declaring protocols might well be imported directly (although youy can use #protocol ABC; to avoid this).
Go ahead and use #import. The only reason people recommend to use #class when possible is because it makes your code slightly faster to compile. However, there is no issue with #importing one .h file from another. In fact, you need to do this when extending another class.
If you are ok using compiler extensions, you could use this order in Clang:
enum Enum;
typedef enum Enum Enum2;
void f(Enum2); // ok. it sees this type's true name.
enum Enum {
E_1
};
// ok. now its declaration is visible and we can use it.
void f(Enum2 e) {
}
Note: It will trigger a -Wpedantic warning.
If you are using C++11, you should use their enums, which are safe to forward declare -- e.g. enum class Enum:uint8_t; (not a compiler extension).
What worked for a forward declaration of an enum for me in an Objective C .h file was look in the ProjectName-Swift.h file and see what it put, which happened to be the following:
enum SwiftEnumName : NSInteger;
I needed this forward declaration because I had a function parameter type of SwiftEnumName. And it wouldn't let me put the ProjectName-Swift.h import in the Objective C .h file.
Then in the Objective C .m file I just had the #import "ProjectName-Swift.h" in it and just used the SwiftEnum normally.
This was using Swift 4.1.2.
You'd have to either #import them anyway or create a separate header file containing only the typedef. Not importing header files in a header makes the compilation faster, but doesn't change anything else.
Why doesn't C++ support forward declaration of enums?