I have this NS_ENUM called ObserveType having two properties called Observe and ObserveAll. I can access the ObserveAll property as you can see from the picture, but I can't access Observe.
The NS_ENUM is in a header file of objective-C.
I know that changing Observe to ObserveX or ObserveXYZ will work.
But how do I access Observe without changing the name of the Observe?
Notice that I have to access the Observe on Swift.
In addition to answers above, I'd like to point out that you can give your Objective-C NS_ENUM a Swift name with NS_SWIFT_NAME macro:
typedef NS_ENUM(NSUInteger, XYZAwesomeEnum) {
XYZAwesomeEnumA,
XYZAwesomeEnumB,
XYZAwesomeEnumC,
} NS_SWIFT_NAME(AwesomeEnum);
Use it later in Swift:
AwesomeEnum.a
Apple Developer: Renaming Objective-C APIs for Swift
From Language Guide - Interoperability - Interacting with C APIs:
"The prefixes to C enumeration case names are removed when they are imported into Swift, whether they’re defined in system frameworks or
in custom code."
This means your first case in the ObserveType enum have no name after being imported to Swift (which I'm somewhat surprised doesn't yield a compile error). If we were to print out the conversion, it would look something like (conceptually)
typedef NS_ENUM(NSInteger, ObserveType) {
Observe = 0
ObserveAll = 1
};
// imported like ...
enum ObserveType: Int {
case _ = 0 // obviously illegal if applied directly in Swift
case All
}
You could try to access the nameless case by using its rawValue (0), but I would recommend updating the name of the first case in your Obj-C enum, if possible.
if let empty = ObserveType(rawValue: 0) {
print(empty) // prints ""?
}
dfri's answer is spot on, and to extend on his answer, it is probably best to name the enum and its cases following the widely adopted conventions. In the following code, I am making certain guesses on your intention.
typedef NS_ENUM(NSUInteger, XYZObserveType) {
XYZObserveOne,
XYZObserveAll
}
Another tip that I find useful when working with projects contain both Swift and Objective-C code is Generated Interface in the source editor.
When you are viewing an Objective-C class, selecting this option will show you the generated Swift header, which can be helpful in many occasions.
Related
So I been used to use this format to declare a enum types:
typedef enum SortType {
SORT_BY_NAME,
SORT_BY_COMPANY,
SORT_BY_NONE
} SortType;
But I saw some people declare it this way
typedef enum {
SORT_BY_NAME,
SORT_BY_COMPANY,
SORT_BY_NONE
} SortType;
Both seems to work and no error. But I want to know which is correct.
I would recommend:
typedef NS_ENUM(NSInteger, SortType) {
SortTypeName,
SortTypeCompany,
SortTypeNone
};
as per the Apple Developer Guides and Sample Code: Adopting Modern Objective-C > Enumeration Macros
Between those two, there isn't a wrong form per se. That said, the current recommended way to declare enums in Objective-C is using the NS_ENUM macro:
typedef NS_ENUM(NSInteger, SortType) {
SORT_BY_NAME,
SORT_BY_COMPANY,
SORT_BY_NONE
};
From Apple's Adopting Modern Objective-C guide:
The NS_ENUM and NS_OPTIONS macros provide a concise, simple way of defining enumerations and options in C-based languages. These macros improve code completion in Xcode and explicitly specify the type and size of your enumerations and options. Additionally, this syntax declares enums in a way that is evaluated correctly by older compilers, and by newer ones that can interpret the underlying type information.
Use the NS_ENUM macro to define enumerations, a set of values that are mutually exclusive:
The NS_ENUM macro helps define both the name and type of the enumeration, in this case named UITableViewCellStyle of type NSInteger. The type for enumerations should be NSInteger.
During a talk at the #Scale 2014 conference (around 32:30), Facebook presented their implementation of a declarative UI approach. The slides for a more detailed version of the talk can be found here.
Basically they presented a function call like this (I made my own simplified example from the example in the talk):
[CPInsetComponent
newWithStyle:{
.margin = 15
}
];
My question is: Is this valid ObjC code? I tried to implement this myself
typedef struct {
uint margin;
} CPInsetComponentStyle;
#interface CPInsetComponent : NSObject
+ (SomeOtherStruct) newWithStyle:(CPInsetComponentStyle)style;
#end
but I still get an "expected expression" error on the newWithStyle:{ line. Could you give me a hint how the method declaration would look like?
No, that's not valid Objective-C code. A C99 compound literal of struct type looks like this:
(TheStructType) { .field1 = initializer1, .field2 = initializer2 }
where the field designators are optional.
I can imagine that the code they were presenting was actually Objective-C++. In C++11, the compiler can insert implicit calls to constructors taking an initializer list if certain conditions are met; hence, often you can pass just an initializer list to a function.
The compiler probably doesn't know if your literal struct declaration is of the correct type. For compound literals you need to provide the type in parenthesis followed by a brace-enclosed list of initializers.
[CPInsetComponent newWithStyle:(CPInsetComponentStyle){
.margin = 15
}];
I was surprised to discover that Xcode does not issue an error for the following code, which is invalid in C:
typedef enum : NSUInteger {
FLAG_A = 1,
FLAG_B = 2,
FLAG_C = 4
} MyFlags;
This appears to make NSUInteger the underlying type of the MyFlags enum, very similar to C#'s syntax for setting the underlying type of an enum.
Does this syntax do what it appears, or does it mean something else?
It is a feature borrowed from C++11 used to ensure a specific size of the enum. It allows to use enums in the public API of frameworks without having to fear that the ABI will eventually break.
Clang implements this feature and allows its use in Objective-C as a language extension.
This will work fine in objective c. you can set any value for these params in an enum.
I've been learning Obj-C since getting a MBP about a month ago. I'm fairly comfortable with what I'm learning & things are slotting in to my rusty old brain pretty well. Except there's one thing I'm just not sure if I'm overlooking, or if just going over my head, or I'm looking for something that isn't there.
Most languages I've used have a way of slotting in an inline function call to simplify the coding, & I'm just not sure how this translates in Obj-C. Especially I'm referring to when the function being called is in a separate file, for the coding purposes of keeping similar functions together.
So far, the only way I've seen in Obj-C guides & tutorials is to create a class with methods & then instantiate that class (within the class you're working) to access the method in a [message]. Is this the way it's done in Obj-C? The only way? The best way for some reason? I know classes have their place in many languages & I use them myself, but I'm referring to simple little inline function calls where I usually wouldn't go to the trouble of creating a complete class.
To use a simple C++ console example of my point (only showing the .cpp files):
// example mainFile.cpp
#include <iostream>
#include "mainFile.h"
#include "functionsFile.h"
using namespace std;
void theMainFunction () {
int resultBeforeAltering = 100;
// alterTheResult() = simple inline function call I'm referring to
cout << "The result is " << alterTheResult(resultBeforeAltering);
}
.
// example functionsFile.cpp - could contain many similar functions
#include "functionsFile.h"
int alterTheResult (int resultToAlter) {
int alteredResult;
if (resultToAlter < 100) {
alteredResult = resultToAlter * 2;
} else {
alteredResult = resultToAlter * 3;
}
return (alteredResult);
}
Is there an equivalent approach to do alterTheResult() in Obj-C (assuming mainFunction() was an Obj-C method)?
I've seen reference to functions within Obj-C, but they seem to be C functions being referred to. C functions are not what I'm asking about here.
Thanks in advance, answers much appreciated.
Yes, the way to inline is to use C or C++ inlining -- that's perfectly legal (for C++, that will require compiling as ObjC++). An ObjC method will never be inlined (until LLVM produces a JIT compiler =p).
If you simply want to organize methods in another file, you may want to try an ObjC category:
// NSString_MONStuff.h
#interface NSString (MONStuff)
- (BOOL)mon_isPalindrome;
#end
// NSString_MONStuff.m
#implementation NSString (MONStuff)
- (BOOL)mon_isPalindrome { return ...; }
#end
Again, those will not be inlined.
You can also use C or C++ external functions or classes instead of categories for organization - the benefit is speed, size, reduced dependencies, and safety. The choice is yours, but there's no way to inline an objc method (it's a very dynamic langauge).
I was looking through the NSString header file to see how Apple writes their enumerations and came across this piece of code:
enum {
NSStringEncodingConversionAllowLossy = 1,
NSStringEncodingConversionExternalRepresentation = 2
};
typedef NSUInteger NSStringEncodingConversionOptions;
This leaves me with a couple questions.
Why have they used anonymous enumerations? Is this method advantageous?
Is the typedef NSUInteger NSStringEncodingConversionOptions; line a good idea to include normally, or is it only used here because they have declared an anonymous enumeration?
That strange-looking definition is there to clearly define the bit-width and the signed-ness of an enum in a code both in 64-bit and 32-bit environment. It's detailed in this Apple document, but let me write down the summary here.
Apple in the past used the standard typedef enums before, as in
typedef enum { .... } NSEnumTypeName;
before 64bit-32bit universal binaries were (re)introduced. (I used "re" because the FAT binaries have been there since the NeXTStep days. Anyway.)
However, this makes the bit-width and the signed-ness of the typedef'd type NSEnumTypeName to be implementation-defined as specified in the Official Standard, see 6.7.2.2.4.
That makes it even trickier to write a code which can be compiled with various compilers and with various bit-width.
So Apple switched from the standard enum to the anonymous enum with a corresponding typedef to a specific signed/unsigned integer type.