I'm more of an Android developer, but i'm beginning to see the light at the end of the tunnel on iOS development.
There is, however, one coding pattern I can't seem to find an equivalent for.
The use of static fields as flags.
Android :
public final static int ERROR_EMPTY = 1;
public final static int ERROR_NO_CONNECTION = 2;
public final static int ERROR_WRONG_USER = 4;
...
if (error == MyClass.ERROR_EMPTY) {//do things}
What would be the proper way to achieve this on iOS ?
Thanks.
Using Objective-C and C
i often use prefixes:
typedef enum MyClass_Error {
// never use MyClass_Error_Undefined
// or you may favor MyClass_Error_None for a valid error code
MyClass_Error_Undefined = 0,
MyClass_Error_Empty = 1,
MyClass_Error_NoConnection = 2,
MyClass_Error_WrongUser = 4
// ...
} MyClass_Error;
for these value collections. then you get benefits such as typesafety and switch value checking.
for non-type constants:
enum { MyClass_ConstantName = 4 };
and feel free to hide these in the *.m when private.
also note that C enums may have gaps in their defined values (unlike Java's).
Update: there's an even better way to declare an enum, as demonstrated in Abizern's answer -- if you're sticking with the most recent toolchains. the big reason to use this extension is for binary compatibility and encoding (although i favor fixed-width types for these purposes).
There are a few other variations, for the cases when you want to use existing types:
Private Constant
MyClass.m
static const NSRange MyClass_InputRange = {1,1};
Public Constant
MyClass.h
extern const NSRange MyClass_InputRange;
MyClass.m
const NSRange MyClass_InputRange = {1,1};
Using C++
You would likely favor introducing a new scope for these values -- either in a class or a namespace, rather than simulating the scope using prefixes.
Common Mistakes
Use of #define for constants (unless definition is mandatory when preprocessing)
Use of short identifiers, and identifiers which are not prefixed
Use of static values in headers
Not using const when possible
Declaring them in the header, when they could be in the *.m source.
Just to add to Justin's excellent answer - the Modern Objective-C definition for the enum would be:
typedef enum MyClass_Error : NSUInteger {
// never use MyClass_Error_Undefined
// or you may favor MyClass_Error_None for a valid error code
MyClass_Error_Undefined = 0,
MyClass_Error_Empty = 1,
MyClass_Error_NoConnection = 2
// ...
} MyClass_Error;
Related
I have define #define baseUrl [NSString stringWithFormat:#"%#api/v4", MAINURL] in objective c class and can access anywhere in project. But now i have created swift file in exiting objective c project and want to access baseurl in swift but error received.
Use of unresolved identifier 'baseUrl'
how can resolve it?
Importing Objective-C macros into Swift doesn't always work. According to documentation:
Swift automatically imports simple, constant-like macros, declared with the #define directive, as global constants. Macros are imported when they use literals for string, floating-point, or integer values, or use operators like +, -, >, and == between literals or previously defined macros.
C macros that are more complex than simple constant definitions have no counterpart in Swift.
An alternative in your case would be to use a function that returns the value defined by macro
// .h file
#define baseUrl [NSString stringWithFormat:#"%#api/v4", MAINURL]
+ (NSString*) BaseUrl;
// .m file
+ (NSString*) BaseUrl { return baseUrl }
Unfortunately, Objective-C #define could not access by swift.
Maybe you change your #defines to actual constants, which is better than #defines.
Or create a swift object hold some static variable.
For example:
class API: NSObject {
static let apiPrefix = "https://vvv"
static let apiPosts = apiPrefix + "posts"
}
Calling: API.apiPosts
I am pretty new to Swift, and I don't have much exposure to C.
I am trying to write a function in C that will get a Swift string that I can then do something with. The problem is that I'm not 100% sure what the type should be in Swift to make C like what it sees.
So far, I have found several examples on Stack that seem like good starting points, but some examples seem dated for the current version of Swift.
I first started by using this example to get C and Swift talking to one another: Swift call C call Swift? I then took that and tried updating the Swift function to return a string of some kind. I understand that it needs to be a UTF-8 return type, but I'm not sure how to go about sending things properly. I've looked at How to pass a Swift string to a c function?, How to convert String to UnsafePointer<UInt8> and length, and How to convert string to unicode(UTF-8) string in Swift?, but none of them really work for a solution. Or I'm just typing it in incorrectly. So far, the closest I can get to returning something is as follows.
In Swift, my ViewController is:
import UIKit
class ViewController: UIViewController {
#_silgen_name("mySwiftFunc") // give the function a C name
public func mySwiftFunc(number: Int) -> [CChar]
{
print("Hello from Swift: \(number)")
let address: String = "hello there";
let newString = address.cString(using: String.Encoding.utf8)
return newString!
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
blah()
}
}
And in C, the header is like:
#ifndef cfile_h
#define cfile_h
#include <stdio.h>
const char * mySwiftFunc(int);
int blah(void);
#endif /* cfile_h */
And the source is like:
#include "cfile.h"
int blah() {
const char * retVal = mySwiftFunc(42); // call swift function
printf("Hello from C: %s", retVal);
return 0;
}
There is a bridging header file that just has #include "cfile.h". Obviously, there is still a lot of remnants from the first example, and these will be cleaned up later.
What needs to change to make this work? Right now, the console spits out
Hello from Swift: 42
Hello from C: (B\214
The Swift equivalent of const char * is UnsafePointer<CChar>?, so that's the correct return value. Then you have to think about memory management. One options is do allocate memory for the C string in the Swift function, and leave it to the caller to release the memory eventually:
public func mySwiftFunc(number: Int) -> UnsafePointer<CChar>? {
print("Hello from Swift: \(number)")
let address = "hello there"
let newString = strdup(address)
return UnsafePointer(newString)
}
passes a Swift string to strdup() so that a (temporary) C string representation is created automatically. This C string is then duplicated. The calling C function has to release that memory when it is no longer needed:
int blah() {
const char *retVal = mySwiftFunc(42);
printf("Hello from C: %s\n", retVal);
free((char *)retVal);
return 0;
}
⚠️ BUT: Please note that there are more problems in your code:
mySwiftFunc() is an instance method of a class, and therefore has an implicit self argument, which is ignored by the calling C function. That might work by chance, or cause strange failures.
#_silgen_name should not be used outside of the Swift standard library, see this discusssion in the Swift forum.
A slightly better alternative is #_cdecl but even that is not officially supported. #_cdecl can only be used with global functions.
Generally, calling Swift functions directly from C is not officially supported, see this discussion in the Swift forum for the reasons and possible alternatives.
In Unity3D we are able to make a field accessible inside the editor by marking it as public. This then allows assigning the field's variable in the GUI instead of hard-coding it. This C# code for example will show a "speed" field that can be manually edited during development. It will default to 10 if left unmodified:
public class Example : MonoBehaviour {
public float speed = 10.0F;
}
I tried doing this in F# with automatic properties:
type Example() =
inherit MonoBehaviour()
member val speed = 10.f with get,set
but this doesn't work. It does, however, work if I use explicit properties
[<DefaultValue>] val mutable speed : float32
but this has the drawback of not being able to specify a default value in the same expression.
Aren't explicit and automatic properties compiling down to the same thing, with the only difference being that explicit properties are always initialized to zero? And how can I declare the equivalent of the C# code in F#?
I think you are playing a little loosely with the terms "field" and "property".
The Unity editor doesn't bind properties automatically, and the first example you've provided is F#'s auto-properties. For the record, you couldn't bind the following C# in Unity editor pane either:
// does not bind in editor either
class Example : MonoBehavior {
public float speed { get; set; }
}
You have to use the code with [DefaultValue] and just initalize it in the constructor or alternatively have a let-bound private field that is tagged [SerializeField] and write your own property wrapper:
type Example () =
[<SerializeField>]
let mutable _speed = 10f
member this.speed
with get () = _speed
and set val = _speed <- val
I think you're confusing two different concepts: explicit fields and auto-properties. Under the hood, a property is more like a method than a field, although access/assignment are syntactically similar. The F# equivalent of your C# would be:
type Example() as this =
[<DefaultValue>] val mutable public speed: float32;
do this.speed <- 10.0f
Another way to implement this, which avoids the [<DefaultValue>] and imperative initialization, would be as follows (note the absence of default constructor on the first line):
type Example =
val mutable public speed : float32
new() = { speed = 10.0f }
I have looked at some other similar questions on SO, but they don't appear to address the following specifically.
What I want to achieve is to have compile-time constants that cannot be altered.
I have a program which I reorganized a little in order to de-clutter. The program had some const declarations prior to "main()". I moved these to a class, however it required that I declare them as "static const". I then thought, ok those other "const" declarations prior to "main()" should probably also be "static const". However when I attempted that, the Editor advised "Top-level declarations cannot be declared to be 'static'". EG.
static const int I_CORRECT_YN = 12; // prompt nr.
So, I am a little confused. I thought that a "const" was static. Why do I have to declare "static" in the class? Why can't I declare a "top level" const as "static"? Also, what is the difference between:
static const int I_CORRECT_YN = 12;
const int I_CORRECT_YN = 12;
static final int I_CORRECT_YN = 12;
final int I_CORRECT_YN = 12; ?
What is the best or only way to declare compile-time values that cannot be altered?
I guess I am looking at the literal meaning, but I presume there is a more complex meaning.
Why do I have to declare "static" in the class?
Because instance variables/methods can't be const. This would mean their value could be different per instance, which can't be the case for compile-time constants. (Source)
Why can't I declare a "top level" const as "static"?
The static modifier marks variables/methods as class-wide (same value for every instance of the class). Top-level stuff is application-wide and doesn't belong to any class, so marking them as class-wide doesn't make any sense and is not allowed. (Source)
What is the best or only way to declare compile-time values that cannot be altered?
You are already doing it - add static when defining class constants. Don't add it when defining top-level constants. Also, use const. final vars aren't compile-time values.
What is the difference between [source code with different constant definitions omitted]
static const and const is the pretty much the same, usage depends on context.
The difference between const and final is that const are compile-time constants - they can only be initialized using literal values (or expressions constisting of operators and literal values) and can't be changed. final variables also can't be changed after being initialized, but they are basically normal variables. This means any kind of expression can be used, and the value can be a different one for every class instance:
import "dart:math";
Random r = new Random();
int getFinalValue() {
return new Random().nextInt(100);
}
class Test {
// final variable per instance.
final int FOO = getFinalValue();
// final variable per class. "const" wouldn't work here, getFinalValue() is no literal
static final int BAR = getFinalValue();
}
// final top-level variable
final int BAZ = getFinalValue();
// again, this doesn't work, because static top-level elements don't make sense
// static final int WAT = getFinalValue();
void main() {
Test a = new Test();
print(Test.BAR);
print(BAZ); // different from Test.BAR
print(a.FOO);
a = new Test();
print(Test.BAR); // same as before
print(BAZ); // same as before
print(a.FOO); // not the same as before, because it is another instance,
// initialized with another value
// but this would still be a syntax error, because the variable is final.
// a.FOO = 42;
}
I hope this helped, and I didn't descibe it too confusing. :]
I'm working on a F# console application. In the properties I set the output type of application to Windows Application to hide the console. I also created a form to run in its place. Currently I only have a simple form with no controls. To make the form I added referances to System.Windows.Forms and System.Drawing and opened them along with System.Runtime.InteropServices.
The part that I don't know how to do is extending the aero-glass. There are loads of exaples on how to do it in C#. For example, here is the API call and MARGINS structure:
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[DllImport("dwmapi.dll")]
pubic static extend int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
The API call from Form_Load event:
MARGINS margins = new MARGINS();
margins.cxLeftWidth = 0;
margins.cxRightWidth = 100;
margins.cyTopHeight = 0;
margins.cyBottomHeight = 0;
int result = DwmExtendFrameIntoClientArea(this.Handle, ref margins);
This is what I've got so far in F#:
The API call and MARGINS structure:
[<StructLayout(LayoutKind.Sequential)>]
type MARGINS =
struct
val cxLeftWidth : int
val cxRightWidth : int
val cyTopHeight : int
val cyBottomHeigh t: int
new(left, right, top, bottom) = { cxLeftWidth = left; cxRightWidth = right; cyTopHeight = top; cyBottomHeigh = bottom } (*Is there any other way to do this?*)
end
[<DllImport("dwmapi.dll")>]
extend int DwmExtendFrameIntoClientArea(IntPtr hWnd, (*I need help here*))
The API call from Form_Load event:
let margins = new MARGINS(0, 100, 0, 0); (*Is there any other way to do this?*)
let result : int = DwmExtendFrameIntoClientArea(this.Handle, (*I need help here*))
I have been searching around but I can't find anything about using ref parameters like this in F#. I know this would be a lot easier to write in C# but the code behind the form will be easier to write int F# because it's a functional programing language and the whole program I'm writing is orientated around functions. I know this is purely decorative but please help.
In general, extern (AKA P/Invoke or platform invoke) definitions in F# use C-like syntax (and note that it's extern, not extend):
[<DllImport("dwmapi.dll")>]
extern int DwmExtendFrameIntoClientArea(nativeint hWnd, MARGINS& pMarInset)
This can then be used as follows:
let mutable margin = ...
let result = DwmExtendFrameIntoClientArea(this.Handle, &margin)
Note that the way that you have defined MARGINS is not quite analogous to the C# definition. The various val definitions are not mutable, and are actually properties rather than fields (though they're backed by fields, so it's probably not a big deal). If you want them to be mutable fields, you can add the mutable keyword after val for each field:
[<Struct; StructLayout(LayoutKind.Sequential)>]
type MARGINS =
val mutable cxLeftWidth : int
val mutable cxRightWidth : int
val mutable cyTopHeight : int
val mutable cyBottomHeight: int
(I've also used the Struct attribute instead of struct ... end, but that's just for brevity). You can initialize this like you do in C#, or using F#'s named arguments:
let mutable margin = MARGINS(cxRightWidth = 100)