How do I access an enum in Swift from Objective-C? - objective-c

There is a global enum defined in Objective-C:
typedef enum {
UMSocialSnsTypeNone = 0,
UMSocialSnsTypeQzone = 10,
UMSocialSnsTypeSina = 11, //sina weibo
} UMSocialSnsType;
This code sets the sharetype of a platform:
snsPlatform.shareToType = UMSocialSnsTypeDouban;
In Swift, I want to get the sharetype of the platform:
var snstype = snsPlatform!.shareToType
println(snstype)
Result: UMSocialSnsType (has 1 child)
snstype.toRaw()
Error: UMSocialSnsType does not have a member named "toRaw"

From what I can tell, UMSocialSNSType was declared in Objective-C without using the NS_ENUM macro, so it wasn't imported as a Swift enum. That means that instead of being able to use .toRaw() or UMSocialSNSType.Douban you have to use the different enumeration values as constant structs. Unfortunately the type also doesn't have the appropriate operators (== or ~=) set up, so you have to compare the value property.
var snstype = snsPlatform!.shareToType
switch snstype.value {
case UMSocialSnsTypeDouban.value:
println("douban")
case UMSocialSnsTypeEmail.value:
println("email")
default:
println("other")
}
if snstype.value == UMSocialSnsTypeDouban.value {
println("douban")
}
The good news is that it looks like all the constants autocomplete in Xcode, so you should be able to do find the comparisons you need to do that way.
It looks like the Swift-version of the bridged typedef...enum must be something like:
struct UMSocialSnsType {
var value:Int
init(_ val:Int) {
value = val
}
}
let UMSocialSnsTypeNone = UMSocialSnsType(0)
let UMSocialSnsTypeQzone = UMSocialSnsType(10)
let UMSocialSnsTypeSina = UMSocialSnsType(11)
// etc
Whereas if it had been declared in Objective-C with the NS_ENUM macro, it would look like:
enum UMSocialSnsType: Int {
case UMSocialSnsTypeNone = 0
case UMSocialSnsTypeQzone = 10, UMSocialSnsTypeSina // etc.
}

Related

Extract value out of Kotlin arrow Either type and assign it to const

It would be a basic question, but I couldn't figure out a solution. I need to initialize a constant out of the right-side value of below either type.
val test: Either<String, Int> = 1.right()
I tried something like below but it shrinks the scope of the constant.
when(test) {
is Either.Right -> {val get:Int = test.b}
is Either.Left -> println(test.a)
}
I want that get to be scoped outside of when statement. Is there any way to do it or Arrow Either is not made for this purpose?
The important question is: what should happen if the Either is Left. In this example it is created close to where it's used, so it is obvious to you as a developer. But to the compiler what is inside the Either can be either an Int or a String.
You can extract the value using for example fold:
val x = test.fold({ 0 }, {it}) // provide 0 as default in case the Either was a `Left`
// x = 1
another option is getOrElse
val test = 1.right()
val x = test.getOrElse { 42 } // again, default in case it was a `Left`
// x = 42
You can also work with it without unwrapping it:
val test = 1.right()
val testPlus10 = test.map { it + 10 } // adds 10 to `test` if it is `Right`, does nothing otherwise
val x = testPlus10.getOrElse { 0 } // unwrap by providing a default value
// x = 11
For more example check the official docs.
Recommended reading: How do I get the value out of my Monad

Is it possible to create an optional literal in Swift?

I have explained my query in the code snippet below. I am looking for this type of syntax for Obj-C interoperability. Specifically I see a difference in behaviour of aCoder.encode(count, forKey: "count") API when count is Int (non-optional) vs Int? (optional)
import Foundation
let num = 5
// Swift's type system will infer this as Int (non-optional)
print(type(of: num))
// Prints: Int
let optNum: Int? = 5
// This is explicitly typed as an optional Int
print(type(of: optNum))
// Prints Optional<Int>
Is it possible to use a literal to implicitly type a var/let to optional?
// let imlicitOptional = 5?
// print(type(of: imlicitOptional))
// The above line should print: Optional<Int>
// or
// let imlicitOptional = num?
// print(type(of: imlicitOptional))
// The above line should print: Optional<Int>
Optional is a plain enum not any specific magic type. So, you can create a value using Optional:
let implicitOptional = Optional(5)
print(type(of: implicitOptional)) // Optional<Int>
I don't know why you need this but you can do like this
let opt = 5 as Int?
// or
let opt = Optional(5)
// or
let opt = 5 as Optional // thanks to vacawama for this
Actually you can even create an operator that returns an optional but I think it's kinda useless.
postfix operator >?
postfix func >?<T>(value: T) -> T? {
return Optional(value) // or return value as T?
}
let a = 5>?

Getting UnsafeBufferPointer from ObjC

In my ObjC-Swift bridging I currently use
- (double*)vector {
return (double*)self.ndArray->vector();
}
- (long) size {
return self.ndArray->size();
}
to create an array in Swift like
let p = vector.vector()
let s = vector.size()
let a = Array<Double>(UnsafeBufferPointer(start: p, count: s))
Would it be possible to get this directly from ObjC like
let a = Array<Double>(vector.readyPackedPointer())
?
A C pointer does not contain any information about the size of the pointed-to memory region, so you'll always have to pass both pointer and count
from (Objective-)C to Swift. You could pass a struct containing both
pointer and count to save a function call.

Assigning to enum value to incompaitable type int

I am using the c++ library. so i converted my .m file to .mm file.
Now what happens i am not able to set the enum value.
See Enum
typedef enum{
ImageSourceTypeCamera,
ImageSourceTypePhotoLibrary,
ImageSourceTypeNone
}
ImageSourceType;
// Property
#property(nonatomic,assign) ImageSourceType ImageSourceType;
Now when i am using this line its give me error
self.ImageSourceType=2; / / assigning to 'ImageProcessType' from incompaitable with 'int'
Try:
self.ImageSourceType = ImageSourceTypePhotoLibrary
To use numbers instead of names for enums, format the definition like so:
typedef enum{
ImageSourceTypeCamera = 0,
ImageSourceTypePhotoLibrary = 1,
ImageSourceTypeNone = 2
}
ImageSourceType;
self.ImageSourceType = 0; //ImageSourceTypeCamera
self.ImageSourceType = 1; //ImageSourceTypePhotoLibrary
//etc...
if (self.ImageSourceType == 0) {
//this is the same as (self.ImageSourceType == ImageSourceTypeCamera)

Is there anything like a Java enum in Objective-C?

I have a situation in Objective-C where a Java-style enum would be very helpful. I have a set of layer types, and each layer has its own persistence value associated with it (stored in seconds). I want to keep these layer types in an enum, since they're too similar to make into separate classes, like so:
typedef enum {
ExplosionLayerType,
FireworkLayerType,
FireLayerType,
FireJetLayerType
} FXLayerType;
In Java, I could easily associate these two values with something like this:
public enum FXLayerType {
Explosion(3),
Firework(6),
Fire(7),
FireJet(-1);
private int persistence;
FXLayerType(int persistence) {
this.persistence = persistence;
}
}
Is there a simple way to create a sort of lightweight class like this in Objective-C, or will need to resort to more primitive methods?
EDIT:
Various people have suggested doing something like this:
typedef enum {
ExplosionLayerType = 3,
FireworkLayerType = 6
} FXLayerType;
This will not work for me, since I may have something like this (Java-style enum):
Explosion(3),
Firework(6),
Dust(3);
In Java, Dust and Explosion will be treated as unique values, but direct assignment with C enums will treat them as being exactly the same.
If you just want a primitive container for type and value, consider this approach:
typedef struct FXLayerValue {
FXLayerType type;
int value;
} FXLayerValue;
Then again, a class hierarchy may be worth consideration if things become complex or are better handled dynamically. Caveat: if you have a ton of objects to save and/or create, an objc type will be overkill and degrade performance.
Unfortunately, my Java-Fu isn't good enough to know all the lang differences for enums.
To emulate Java enum's we need something which is comparable (can be operands of == etc.), which can have fields, and is lightweight. This suggests structs, and optionally pointers to structs. Here is an example of the latter:
FXLayerType.h:
typedef const struct { int persistence; } FXLayerType;
extern FXLayerType * const LayerTypeExplosion;
extern FXLayerType * const LayerTypeFirework;
extern FXLayerType * const LayerTypeDust;
FXLayerType.m:
#import "FXLayerType.h"
const FXLayerType _LayerTypeExplosion = { 3 };
const FXLayerType _LayerTypeFirework = { 6 };
const FXLayerType _LayerTypeDust = { 3 };
FXLayerType * const LayerTypeExplosion = &_LayerTypeExplosion;
FXLayerType * const LayerTypeFirework = &_LayerTypeFirework;
FXLayerType * const LayerTypeDust = &_LayerTypeDust;
So FXLayerType itself is a constant struct, while as with Obj-C objects we always use pointers to these structs. The implementation creates 3 constant structs and 3 constant pointers to them.
We can now write code such as:
FXLayerType *a, *b;
a = LayerTypeDust;
b = LayerTypeExplosion;
NSLog(#"%d, %d\n", a == b, a->persistence == b->persistence);
Which will output "0, 1" - a and b are different enums (0) but have the same persistence (1). Note here a and b are not constant pointers, only the enum "literals" are defined as constants.
As written this has the disadvantage that you cannot switch on an enum value. However if that is needed just add a second field, say tag, and init it with a unique value using a real enum, say FXLayerStyleTag. You can also remove the indirection if you are happy to always compare tags (e.g. a.tag ==b.tag`). This gives you:
FXLayerType.h:
typedef enum { ExplosionTag, FireworkTag, DustTag } FXLayerTypeTag;
typedef struct { FXLayerTypeTag tag; int persistence; } FXLayerType;
extern const FXLayerType LayerTypeExplosion;
extern const FXLayerType LayerTypeFirework;
extern const FXLayerType LayerTypeDust;
FXLayerType.m:
#import "FXLayerType.h"
const FXLayerType LayerTypeExplosion = { ExplosionTag, 3 };
const FXLayerType LayerTypeFirework = { FireworkTag, 6 };
const FXLayerType LayerTypeDust = { DustTag, 3 };
Use:
FXLayerType a, b;
a = LayerTypeDust;
b = LayerTypeExplosion;
NSLog(#"%d, %d\n", a.tag == b.tag, a.persistence == b.persistence);
A difference between the two designs is the first passes around pointers while the second structures, which may be larger. You can combine them, to get switchable pointer-based enums - that is left as an exercise!
Both these designs also have the (dis)advantage that the number of enum "literals" can be extended at any time.
Actually you may assign values to the enum keys in C, as they are nothing but ints:
typedef enum {
LayerTypeExplosion = 3,
LayerTypeFirework = 6,
LayerTypeFire = 7,
LayerTypeFireJet = -1
} FXLayerType;
You may use them then simply as a restricted set of values, to be assigned to a variable of type FXLayerType.
FXLayerType myLayerType = LayerTypeFirework;
NSLog(#"Value of myLayerType = %i", myLayerType);
// => "Value of myLayerType = 6"
This is not 100% equivalent, but this might be an approach you could take in Objective-C. Basically, create several class-level convenience methods to construction the various configuration of FXLayerType.
#interface FXLayerType
{
#private
int persistence;
}
+ (FXLayerType*)fireworkLayerType;
+ (FXLayerType*)explosionLayerType;
+ (FXLayerType*)jetLayerType;
#end
#implementation FXLayerType
+ (FXLayerType*)explosionLayerTypeWithPersistence:(int)persistence
{
FXLayerType* layerType = [[FXLayerType new] autorelease];
layerType->persistence = persistence;
return layerType;
}
+ (FXLayerType*)explosionLayerType
{
return [self explosionLayerTypeWithPersistence:3];
}
+ (FXLayerType*)fireworkLayerType
{
return [self explosionLayerTypeWithPersistence:6];
}
+ (FXLayerType*)jetLayerType
{
return [self explosionLayerTypeWithPersistence:-1];
}
#end
Usage:
FXLayerType* aJetLayerType = [FXLayerType jetLayerType];
I have recently used the j2objc format for enums. It works rather nicely. Additionally you can auto generate your enums if you are trying to map directly from a java object.
https://code.google.com/p/j2objc/wiki/Enums
However, I did remove the j2objc specific classes from my "Enums". I did not want the additional dependencies.
The struct based answers look good on their face but fail when you try to add Objective-C objects into the struct. Given that limitation, truly emulating the Java-style enum may be more work than it is worth.