What is proper way to forward declare NS_OPTIONS in Objective-C\C++ - objective-c

I'm generating bridges from cpp to swift using cpp-objcpp-objc chain and I need to generate NS_OPTIONS.
In ObjC I have it as follows:
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(NSInteger, PhonebookPhoneOptions)
{
PhonebookPhoneOptionsOpt1 = 1 << 0,
PhonebookPhoneOptionsOpt2 = 1 << 1,
PhonebookPhoneOptionsOpt3 = 1 << 2,
PhonebookPhoneOptionsOpt4 = 1 << 3,
};
It is forward-declared in my another header
#import <Foundation/Foundation.h>
typedef NS_OPTIONS(NSInteger, PhonebookPhoneOptions);
//typedef NS_ENUM(NSInteger, PhonebookPhoneOptions);
#protocol PhonebookDataRefreshedCallback
- (void)onEvent:(PhonebookPhoneOptions)param;
When I use NS_OPTIONS forward declaration I'm getting following error:
With NS_ENUM forward it is as folows:
subprojects/controller/service-sbis-phonebook/phonebook/djinni/objc/phonebook/PhonebookDataRefreshedCallback.h:5:53:
error: unnamed enumeration must be a definition typedef
NS_OPTIONS(NSInteger, PhonebookPhoneOptions);
subprojects/controller/service-sbis-phonebook/phonebook/djinni/objc/phonebook/PhonebookDataRefreshedCallback.h:5:9:
error: declaration does not declare anything
[-Werror,-Wmissing-declarations] typedef NS_OPTIONS(NSInteger,
PhonebookPhoneOptions);
With NS_ENUM it is as follows:
subprojects/controller/service-sbis-phonebook/phonebook/djinni/objc/phonebook/PhonebookPhoneOptions.h:6:31:
error: typedef redefinition with different types ('NSInteger' (aka
'long') vs 'enum PhonebookPhoneOptions') typedef NS_OPTIONS(NSInteger,
PhonebookPhoneOptions)
subprojects/controller/service-sbis-phonebook/phonebook/djinni/objc/phonebook/PhonebookDataRefreshedCallback.h:5:28:
note: previous definition is here typedef NS_ENUM(NSInteger,
PhonebookPhoneOptions);
When it was used solely as structure field I got some combination of NS_ENUM\NS_OPTIONS in ObjC\ObjC++ that was working, but when I try to use it as a function argument - it doesn't compile in any of the variants. What is the correct way to do such forward declaration?

I don't think there's a way to forward declare these sensibly. Can't you simply pack the definition into a header file with no other content so it can be #included from just about anywhere? So, have a header file that contains nothing other than your enum, then include/import that from anything that needs it without pulling in any transitive dependencies.
If your problem is that NS_ENUM/NS_OPTIONS isn't available in pure C++, or rather, that #include <Foundation/Foundation.h> does not work there, try CF_ENUM/CF_OPTIONS instead, which are equivalent and defined in <CoreFoundation/CFAvailability.h>, which can be used from any of the C/C++/ObjC/ObjC++.
If that doesn't help you, please update your question to explain in more detail why you are trying to forward declare your enum type. As in, what specific problem arises as a result of not forward declaring the type? (provide minimal repro code)

Related

typedef NS_ENUM vs typedef enum

On the Adopting Modern Objective-C guide, Apple recommends using the NS_ENUM macro instead of enum. I've also read an explanation from NSHipster about NS_ENUM and NS_OPTIONS.
Maybe I've missed something but I don't quite understand what is the difference between the following two snippets and if any why is NS_ENUM the recommended way to go (except maybe, for backwards compatibility with older compilers)
// typedef enum
typedef enum {
SizeWidth,
SizeHeight
}Size;
// typedef NS_ENUM
typedef NS_ENUM(NSInteger, Size) {
SizeWidth,
SizeHeight
};
First, NS_ENUM uses a new feature of the C language where you can specify the underlying type for an enum. In this case, the underlying type for the enum is NSInteger (in plain C it would be whatever the compiler decides, char, short, or even a 24 bit integer if the compiler feels like it).
Second, the compiler specifically recognises the NS_ENUM macro, so it knows that you have an enum with values that shouldn't be combined like flags, the debugger knows what's going on, and the enum can be translated to Swift automatically.
NS_ENUM allows you to define a type. This means that the compiler can check if you're assigning the enum to a different variable like so:
//OK in both cases
NSInteger integer = SizeWidth;
//OK only with typedef
BOOL value = SizeHeight;
NS_ENUM also provides checks in switch statements that you've covered all possible values:
//Will generate warning if using NS_ENUM
switch(sizeVariable) {
case SizeWidth:
//Do something
}

ObjC category on typedef class: "cannot find interface declaration for 'typedefname'"

This code gives me the error Cannot find interface declaration for 'OGWView':
typedef SKNode OGWView;
#interface OGWView (Category)
#end
Why? Shouldn't the category work just as well with a typedef name?
PS: I know I can fix this with a #define (or by using the original class name) but I'm really more interested in understanding why it isn't possible to create a category on a typedef class.
I believe the answer to this question is that you have 2 different kinds of symbol. I believe the typedef is an object and you are trying to use it as a class symbol.
depending on the order of declaration you get different warnings suggesting as much:
typedef NSObject Foo;
#class Foo;
yields:
Redefinition of forward class 'Foo' of a typedef name of an object type is ignored
#class Foo;
typedef NSObject Foo;
yields:
Redefinition of 'Foo' as different kind of symbol
Replace typedef with #compatibility_alias
#compatibility_alias SKNode OGWView;

I am having all the time this issue after running my app

I don't know why, but after a while working without problems I added some buttons, then I launched my app and this error appeared:
ld: duplicate symbol _x in
/Users/alexbarco/Library/Developer/Xcode/DerivedData/RecolectaDatos-ayjpqqcajbhuzvbkvernzsyunpbe/Build/Intermediates/RecolectaDatos.build/Debug-iphonesimulator/RecolectaDatos.build/Objects-normal/i386/SeconViewController.o
and
/Users/alexbarco/Library/Developer/Xcode/DerivedData/RecolectaDatos-ayjpqqcajbhuzvbkvernzsyunpbe/Build/Intermediates/RecolectaDatos.build/Debug-iphonesimulator/RecolectaDatos.build/Objects-normal/i386/ViewController.o
for architecture i386 clang: error: linker command failed with exit
code 1 (use -v to see invocation)
Whenever I have duplicate symbol errors, it is almost always because I have a circular #import in my headers. The solution is quite simple, use forward declarations where possible, and #import .h files from .m files instead.
There are just two cases where you need to #import one .h from another:
if you are extending the class in the #import
you are implementing a protocol in the #import
Specifically, you do not need to import files just to use a class name or protocol in your signatures; instead use forward declarations.
For example, this (in Bar.h):
#import "Foo.h"
might become this (Bar.h):
#class Foo;
#protocol FooDelegate;
and bar.m:
#import "Foo.h"
Here is a link to the documentation on forward declarations.
The "duplicate symbol" message means that you're declaring some name (in this case, _x) twice in the same scope. Say you had code like this:
int _x = 1;
int _x = 2;
You'd expect to get an error then, right? You can use the same name for two things at the same time.
The error you're getting is essentially the same. You're declaring _x somewhere, and from the compiler's point of view you're doing it twice. There are a few ways to deal with this, depending on what _x represents.
chrahey's answer explains about forward class declarations. I won't cover that again here except to say that a forward declaration helps you resolve circular references, where the definition of class A depends on class B and vice versa.
If _x is a variable, it's likely that you're trying to declare it in a header file. The compiler basically copies the contents of each header file that you import into the source file, so if you declare a variable in a header file and then import that header into two or more implementation files, you'll end up with multiple declarations of that variable. To get around that, use the extern keyword to tell the compiler "this name will be declared somewhere else" and then put the real declaration in an implementation file:
Foo.h:
extern int _x;
Foo.m
int _x;
Pretty much the same thing goes for functions. It doesn't appear that _x is a function, but if it were, and if you were silly enough to put the function definition in a header file, then you'd again get an error if that file were imported into more than one implementation file. This is why header files contain prototypes, not definitions:
Foo.h:
int foo(int a);
Foo.m
int foo(int a)
{
return a + 10;
}

C Header Files - Good Practice

I am used to Objective C header files and am not sure how C header files are used in terms of good practice.
Where would one #include other source files, in the header file or the .c file?
Does the same idea apply to C where .c files include their own header files. and other files include the .h files of the source they want to include?
Is there anything equivalent to the #class usage in Objective-C?
Is it good practice to declare pointers in the .h file and initialize them/alloc them in the .c file?
You normally distinguish between source and header files in the same way that Objective-C differentiates between implementation (.m) and interface (.h) files. Source files contain everything that may execute, header files contain enough information about symbols that other source files know how to communicate with that source file.
Header files often include other header files, so you'll see #include in both source and implementation files. #include operates exactly like #import except that it doesn't automatically check whether you've #included the same file twice. So C header files often look something like:
#ifndef __SOME_SYMBOL
#define __SOME_SYMBOL
... rest of header file here ...
#endif
Which has the same effect of ensuring the main body of the header file is included only once.
EDIT: more on this, as per request. Obviously you'd never do something like:
#include "File.h"
#include "File.h"
But you can easily end up with something like:
#include "FirstComplexThing.h"
#include "SecondComplexThing.h"
Where both FirstComplexThing.h and SecondComplexThing.h rely on something inside and hence #include SimpleThing.h. So you end up with SimpleThing.h #included twice, without making any sort of error or following any bad design pattern.
C compilers work just like Objective-C compilers — each source file is compiled on its own, in isolation, with no overview until the linker comes along. #include is a preprocessor directive that has the same logical effect as copying the contents of the named file and pasting them into your source file at that location, so if you end up the same file #included twice you'll probably end up with something like:
char *somePointer; // I'm from SimpleThing.h
... lots of other things ...
char *somePointer; // I'm from SimpleThing.h
And the compiler will stop with an error that the same thing is declared twice. #import in Objective-C avoids that by being shorthand for '#include, but only if you haven't already #included that file'. The C #ifndef/#define/#endif convention achieves the same thing as #import because the #ifndef/#endif pair say that the stuff in between should be passed on to the compiler if the nominated preprocessor symbol (__SOME_SYMBOL in my example; it tends to be a name derived from the name of that header file but exact conventions vary) hasn't been defined. It won't have been the first time the construct is encountered. Because it is defined inside the construct, it will have been when the same #ifndef is encountered the second time, so the stuff up to the matching #endif won't be passed on.
Although it's a question of style, it is very often the case that each C file has one H file that is directly connected to it.
There are no classes in C, obviously, but if you mean a construct like:
#class SomeClass;
#interface SomeOtherClass: NSObject
{
SomeClass *otherClass; // I can reference SomeClass without importing
// the interface file because I've declared the
// type above
}
- (void)whatever;
#end
That's actually the normal C distinction between declarations and definitions. You'll have a problem if you do something like:
struct SomeStruct;
struct SomeOtherStruct
{
struct SomeStruct otherStruct;
};
Because the compiler doesn't have enough information. It doesn't know how large SomeStruct should be, so it can't work out how SomeOtherStruct should be laid out. However, this is completely valid:
struct SomeStruct;
struct SomeOtherStruct
{
struct SomeStruct *otherStruct;
};
Because the size of a pointer is always known, irrespective of what it is pointing to. You'll often see that C libraries with opaque types describe those types by pointer only (sometimes to void *, but not always — e.g. stdio.h uses FILE *) or just give you an integer (including OpenGL, notably). So they ensure you've something that the compiler will know the size of without having to tell you what data they're associating with it or giving you any way to try to manipulate it yourself.
It's perfectly good practice to put pointers in the header file (assuming it's good practice to expose the thing globally, obviously). The same thing is often done in Objective-C, albeit for slightly different reasons, e.g.
// interface/header file
extern NSString *someGlobalIdentifier;
And:
// implementation/source file
NSString *someGlobalIdentifier = #"somethingOrOther";
In Objective-C that's because you can then test identity rather than always having to test equality, but basically the same rules apply to C with respect to it being normal to put the reference (be it a pointer or whatever) that represents a thing into the header and create or declare the thing in a source file. In fact, if you start putting declarations in the header file you'll end up with errors when the program comes to link because multiple source files will think they declare the thing.
->#include is working in c and objective c.
->But generally in objective c, always used #import.
->#include and #import are different, when you used #include compiler generate one separate copy of .h file, and if you used #import then compiler generate only one copy at a time
Is there anything equivalent to the #class usage in Objective-C?
-> No there is no any other equivalent
Is it good practice to declare pointers in the .h file and initialize them/alloc them in the .c file?
-> Yes if your object is public, then you must declare in .h file, but always is good practice that initialize them it in constructor.
This is how I finally figured out how to do this properly. After long time of trying and failing at what used to be a simple thing.
//this is the mechanics.h file
#ifndef ProjectA_mechanics_h
#define ProjectA_mechanics_h
#ifdef __cplusplus
extern "C" {
#endif
int funcAdd (int A, int B);
#ifdef __cplusplus
}
#endif
#endif
// this is the mechanics.c file
#include "mechanics.h"
#include <math.h>
int funcAdd (int A, int B)
{
return A + B;
}
math.h is there "just because"
have fun, dang this sucked for while

iOS 4 - Using blocks as a member of a class

I was hoping someone could help me understand the syntax of blocks when used as members of a class. I have some code that's actually working just fine:
#class Structure;
typedef void (^StructureDeleteCallback)(Structure *);
#interface StructureListDelegate : NRFCTableDelegate
{
StructureDeleteCallback _structureDeleteCallback;
}
#property (nonatomic, copy) StructureDeleteCallback structureDeleteCallback;
#end
This works, but I would like to understand the syntax of the typedef statement; and whether or not it's actually required to use typedef.
What I've read says that using typedef in this situation is recommended because it makes the code a lot clearer; but I've been unable to get it to compile at all when trying to do this without typedef. My understanding of typedef was that the syntax was basically:
typedef [actual type] [new name for type];
Such as:
typedef double CLLocationDegrees;
But the syntax of my typedef statement doesn't match this. So my questions are:
How can the syntax of my typedef
statement be so different from other
typedef statements / what does the syntax I'm using actually mean to the compiler?
Is it possible to
have a block as a member of a class
without using typedef?
I myself have asked a question along the lines of yours here: Block references as instance vars in Objective-C
See my answers here and here.