I have an enum defined as follows:
typedef enum modifiers {
modifierNone=-1,
modifierCmd,
modifierShift,
modifierOption
} Modifier;
What i would like to do is pass a string value from one method to another for example (modifierCmd) and create the relevant Modifier to pass to a separate method.
- (void)methodOne:(NSString *)stringValue {
Modifier mod = (Modifier)stringValue;
[self methodTwo:mod];
}
Should this work?
Thanks
Nope. You can use a function, though:
Modifier makeModifier(NSString *s)
{
if ([s isEqualToString:#"modifierNone"]) {
return modifierNone;
} else if ([s isEqualToString:#"modifierCmd"]) {
return modifierCmd;
} /* etc... */
}
- (void)methodOne:(NSString *)stringValue
{
[self methodTwo:makeModifier(stringValue)];
}
I don't think it can work because the data type is really different. Enum is in fact, integer, when NSString is an object. You can use if else to check for modifier. But I recommend to pass the modifier directly.
Related
I wanted to use macro to check if a function is returning a particular generic type, say Array, so it is fine if the function is returning Array<Dynamic>, Array<String>, or even generic Array<T>.
So I tried to Context.unify it with Array<Dynamic>. It is fine for Array<String> or Array<Dynamic> but it fails when the type parameter is "generic" because the ComplexType Array<T> won't convert to a Type with Type not found: T (See code below). Are there any possible ways to achieve what I am attempting to do?
package;
#if macro
import haxe.macro.Context;
using haxe.macro.ComplexTypeTools;
#end
#if !macro #:build(Macros.build()) #end
class Main
{
public function test<T>():Array<T>
{
return [];
}
}
class Macros
{
public static function build()
{
#if macro
var fields = Context.getBuildFields();
for(field in fields)
{
switch(field.kind)
{
case FFun(f):
// try to unify Array<String> with Array<Dynamic>
trace(Context.unify((macro:Array<String>).toType(), (macro:Array<Dynamic>).toType()));
// true
// try to unify Array<T> with Array<Dynamic>
trace(Context.unify(f.ret.toType(), (macro:Array<Dynamic>).toType()));
// Type not found: T
default:
}
}
return null;
#end
}
}
UPDATE
So, checking TPath was not the best idea.
Based on the previous assumption about Dynamic being assignable to any type we can replace unconvertable type parameter with the Dynamic (eg Array<T> = Array<Dynamic>) and when try to unify it.
static function toTypeExt(c:ComplexType):Null<haxe.macro.Type>
{
try {
return c.toType();
} catch (error:Error)
{
switch (c)
{
case TPath(p):
//deep copy of the TPath with all type parameters as Dynamic
var paramsCopy = [for (i in 0...p.params.length) TPType(macro:Dynamic)];
var pCopy:TypePath = {
name: p.name,
pack: p.pack,
sub: p.sub,
params: paramsCopy
}
var cCopy = TPath(pCopy);
//convert after
return cCopy.toType();
default:
}
}
return null;
}
Use toTypeExt() in your build macro instead of toType.
trace(Context.unify(toTypeExt(f.ret), (macro:Array<Dynamic>).toType()));
Looks more like a workaround to me, but there is a strange thing about ComplexTypeTools.toType - it will succeed with a class type parameter while failing with method type parameter.
OLD ANSWER
Unification won't work since there is no way of converting ComplexType with the type parameter to Type (in that context). But since you are unifying with Array it is safe to assume that any Array will unify with it (since any type is assignable to Dynamic http://haxe.org/manual/types-dynamic.html).
May be it is not the pritiest solution, but simple TPath check is the way to go here:
case FFun(f):
switch (f.ret) {
case TPath({ name: "Array", pack: [], params: _ }):
trace("Yay!");
default:
}
Is there a difference between a getter computed property and variable that returns a value? E.g. is there a difference between the following two variables?
var NUMBER_OF_ELEMENTS1: Int {
return sampleArray.count
}
var NUMBER_OF_ELEMENTS2: Int {
get {
return sampleArray.count
}
}
A computer property with getter and setter has this form:
var computedProperty: Int {
get {
return something // Implementation can be something more complicated than this
}
set {
something = newValue // Implementation can be something more complicated than this
}
}
In some cases a setter is not needed, so the computed property is declared as:
var computedProperty: Int {
get {
return something // Implementation can be something more complicated than this
}
}
Note that a computed property must always have a getter - so it's not possible to declare one with a setter only.
Since it frequently happens that computed properties have a getter only, Swift let us simplify their implementation by omitting the get block, making the code simpler to write and easier to read:
var computedProperty: Int {
return something // Implementation can be something more complicated than this
}
Semantically there's no difference between the 2 versions, so whichever you use, the result is the same.
They are identical since both define a read-only computed property. But the former is preferable because it is shorter and more readable than the latter.
I want to return the class and function for debugging purposes. In Objective-C I would use the following, how would I do the same in Swift?
Obective-C
if (debug==1) {
NSLog(#"Running %# '%#'", self.class,NSStringFromSelector(_cmd));
}
Swift
if debug==1 {
println("Running: ", self ,__FUNCTION__)
}
In swift, this would return something like this:
(Running: , <myTeamManager.PlayerInformationTableViewController: 0x7fa18bd31680>, viewDidLoad())
but I only want PlayerInformationTableViewController
reflect(self).summary.pathExtension
I am using the wahoo fitness API and it defines the following objective-C enum:
typedef enum
{
/** No active connection. */
WF_SENSOR_CONNECTION_STATUS_IDLE,
/** The connection is in process of being established. */
WF_SENSOR_CONNECTION_STATUS_CONNECTING,
/** The sensor connection is established and active. */
WF_SENSOR_CONNECTION_STATUS_CONNECTED,
/** The connection was interrupted (usually occurs when fisica is disconnected). */
WF_SENSOR_CONNECTION_STATUS_INTERRUPTED,
/** The connection is in process of being disconnected. */
WF_SENSOR_CONNECTION_STATUS_DISCONNECTING,
} WFSensorConnectionStatus_t;
I can't find a way to use it in swift. I first tried to do a switch/case on it without success. I am at a point I just want to carry on and tried the following:
var connState : WFSensorConnectionStatus_t = WF_SENSOR_CONNECTION_STATUS_IDLE
...
if( connState == WF_SENSOR_CONNECTION_STATUS_IDLE){
But it does not compile:
'WFSensorConnectionStatus_t' is not convertible to 'NSObject'
Any workaround? I read to use WFSensorConnectionStatus_t.WF_SENSOR_CONNECTION_STATUS_IDLE or WF_SENSOR_CONNECTION_STATUS_IDLE.value but it does not work in xcode beta-4.
The workaround to use .value to get the underlying integer doesn't work anymore as of Beta 4, as you said.
Unfortunately an enum is not transferrable to Swift from Objective-C, it needs to be an NS_ENUM.
I have the same setup as you in a project where I need the enum from an Objective-C framework and use it in Swift.
The workaround I did was to create an Objective-C category that contains an NS_ENUM and there I transfer the values from the framework enum to my own NS_ENUM.
Import the category in your bridging header and you should be able to use the enum as you normally would do.
Something like this:
typedef NS_ENUM(NSUInteger, ConnectionStatus) {
ConnectionStatusIdle
}
- (ConnectionStatus)connectionStatus {
if [self getConnectionStatus] == WF_SENSOR_CONNECTION_STATUS_IDLE {
return ConnectionStatusIdle
}
}
Then you should be able to use it like this:
switch myObject.connectionStatus() {
case .Idle:
// do something
break
}
Here is the final complete solution:
WFSensorConnection+SensorConnectionEnumCategory.h
:
#import <Foundation/Foundation.h>
#import <WFConnector/WFConnector.h>
#interface WFSensorConnection (SensorConnectionEnumCategory)
typedef NS_ENUM(NSUInteger, ConnectionStatus) {
ConnectionStatusIdle,
ConnectionStatusConnecting,
ConnectionStatusConnected,
ConnectionStatusInterrupted,
ConnectionStatusDisconnecting
};
- (ConnectionStatus) swift_connectionStatus;
#end
WFSensorConnection+SensorConnectionEnumCategory.m
:
#import "WFSensorConnection+SensorConnectionEnumCategory.h"
#implementation WFSensorConnection (SensorConnectionEnumCategory)
- (ConnectionStatus) swift_connectionStatus{
if ( [self connectionStatus] == WF_SENSOR_CONNECTION_STATUS_IDLE ){
return ConnectionStatusIdle;
} else if ( [self connectionStatus] == WF_SENSOR_CONNECTION_STATUS_CONNECTING ){
return ConnectionStatusConnecting;
} else if ( [self connectionStatus] == WF_SENSOR_CONNECTION_STATUS_CONNECTED ){
return ConnectionStatusConnected;
} else if ( [self connectionStatus] == WF_SENSOR_CONNECTION_STATUS_DISCONNECTING ){
return ConnectionStatusDisconnecting;
} else if ( [self connectionStatus] == WF_SENSOR_CONNECTION_STATUS_INTERRUPTED ){
return ConnectionStatusInterrupted;
}
return 0;
}
#end
Bridging-Header.h
:
#import "WFSensorConnection+SensorConnectionEnumCategory.h"
Usage:
var sensorConnection: WFSensorConnection?
var connState : ConnectionStatus = ConnectionStatus.Idle
connState = sensorConnection!.swift_connectionStatus()
switch connState {
case ConnectionStatus.Idle:
...
}
C-style enums import in Swift like UInt32. So you can do something like:
let state = unsafeBitCast(WF_SENSOR_CONNECTION_STATUS_IDLE, UInt32.self)
if state == unsafeBitCast(WF_SENSOR_CONNECTION_STATUS_IDLE, UInt32.self) {
//do something
}
Upd: In Swift 2.1 (Xcode 7.1 beta 2) all C-style enums conforms Equatable and you can now use it like:
let state = WF_SENSOR_CONNECTION_STATUS_IDLE
if state == WF_SENSOR_CONNECTION_STATUS_IDLE {
//do something
}
Profit :)
Note that there is a CoreFoundation type that is similar to NS_ENUM called CF_ENUM. I've used it on my framework that is mainly C. And yes, Swift does translate it to a Swift enum.
There is also something similar for NS_OPTIONS called CF_OPTIONS.
I have a function in which I hope to return different type
-(UIButton *)returnObject1 ;
{
//dosomething
return aUIButton;
}
-(UIView *)returnObject2 ;
{
//dosomething
return aUIView;
}
I hope to merge the two function to one and return different NSObject(UIButton,UIView)
Is it possible?
Welcome any comment
Just don't declare a return type. Change it to this instead:
- (id)returnObject
{
if (something) {
return aUIButton;
}
return aUIView;
}
However... UIButton is a subclass of UIView, which means you can do this instead:
- (UIView *)returnObject
{
if (something) {
return aUIButton;
}
return aUIView;
}
Note that, in objective-c, the return type of a method is completely irrelevant while the code is being executed. The entire purpose is to inform the compiler what your code expects, so that it can avoid crashes. So, specifying a return type is a good idea when possible, but is not necessary.
you can simply create your own custom object that contains both and return that one
Edit: I understood that the OP wanted to return 2 objects. this answer only applies for that case.
Here's an example of what you want:
-(id)returnObject:(int)type
{
if (type == 1)
return aUIButton;
else if (type == 2)
return aUIView;
return nil;
}