I'm sure there is a simple answer to this but I'm banging my head here.
In my Swift 2 code (Xcode 7.2.1) I am using CFByteOrderGetCurrent() to get the byte ordering of the local machine.
I can't figure out how to evaluate the result of the function - the 'if' statement in the following fails compilation with
"type of expression is ambiguous without more context":
import Foundation
let byteOrder = CFByteOrderGetCurrent()
if byteOrder == .CFByteOrderLittleEndian { // compilation fails here
/* do something */
}
From the CF documentation I was to expecting the result of the function to be an enum, but when I try it in a playground it seems to be an Int ...
CFByteOrder is a typealias of CFIndex.
It is an enum, which consists of the following values:
CFByteOrderUnknown,
CFByteOrderLittleEndian,
CFByteOrderBigEndian
Thus, CFByteOrderLittleEndian corresponds to 1.
In order to do the comparison, one may need to do the following:
if byteOrder == CFByteOrder(1)
{
print(byteOrder)
}
1 here corresponds to CFByteOrderLittleEndian.
i am using a little bit different trick ...
if 1.littleEndian == 1 {
print("little endian")
} else {
print("big endian")
}
generally
let isLittleEndian = 1.littleEndian == 1
is true on little endian system, false on big endian system. the advantage is, that it works on all platforms
OK I finally cracked how to make the comparison using symbolic constants.
If you convert the result of CFByteOrderGetCurrent() into a UInt32 then you can compare it to the raw value of the constants in the enumeration:
import Foundation
let hostByteOrder = UInt32(CFByteOrderGetCurrent())
if hostByteOrder == CFByteOrderLittleEndian.rawValue {
print("little")
}
Related
I have an array of the following struct:
struct AtomCameraType
{
var APIIdentifier: Input.HDRCamera
var name: String
init(...
}
That APIIdentifier, of type Input.HDRCamera, is a generated Google Protocol Buffer enum in Swift:
enum HDRCamera: SwiftProtobuf.Enum {
typealias RawValue = Int
case standard // = 1
case sony // = 2
case canon // = 3
case panasonic // = 4
case arri // = 5
case jvc // = 6
case red // = 7
case rec2100 // = 8
case fujifilm // = 9
case nikon // = 10
case proResRaw // = 11
init() {
self = .standard
}
This may not conform to the Equatable protocol.
Attempts to match one of these enums against another with == works in a straight if statement, but fails when using == in firstIndex(where:.
So this works (cameraTypes is the aforementioned array of AtomCameraType):
for testType in AtomCamera.cameraTypes() // array of struct AtomCameraType
{
if testType.APIIdentifier == camType.APIIdentifier
{
debugPrint("Match found.")
}
}
but this doesn't:
if let camIndex = AtomCamera.cameraTypes().firstIndex(where: { $0.APIIdentifier == camType.APIIdentifier })
{
debugPrint("Match found.")
}
but finally, it works if I add rawValue:
if let camIndex = AtomCamera.cameraTypes().firstIndex(where: { $0.APIIdentifier.rawValue == camType.APIIdentifier.rawValue })
{
// This works.
...
}
So it seems to me that == doesn't always need conformance to Equatable, but sometimes it does. Or is there something else going on here?
UPDATE: So, with no changes to this code, it now works. I made extensive changes in the AtomCamera object, but not to these structs or cameraTypes(). And, as you can see from the working/non-working examples (which I had in the code at the same time), they're both using the same call to cameraTypes() to fetch the array.
Returning to this issue, I looked for other firstIndex(where:) calls with similar structs and ==, and found that they worked. So I removed the ".rawValue" from this troublesome one experimentally... to find that the firstIndex now works. Baffling.
What's the protocol here? Delete this or close it, or just leave it?
The == operator "doesn't need" Equatable. In fact, no function, subscript, property or operator requirement of any protocol "needs" its protocol. Being present is a requirement for the protocol, but even without the protocol, nothing prevents an == operator from being defined, no different from any other arbitrary protocol.
I don't know what the definition of cameraTypes() is, but there is no difference between the == operator used in your if statement and that used in the firtIndex(where:) call. I don't know why it's exhibiting different behaviour for you.
Your rawValue example works because the rawValue's type is Int (or some integral type, IDK the specifics of SwiftProtobuf.Enum), which is Equatable (and thus, necessarily has a == operator defined).
While converting from Swift 2.3 to 3.2 I received below error.
Error : Binary operator cannot be applied to operands of type Int and String
for this if Condition i.e if (error?.code)! == "-112" which is shown in below line.
if (error?.code)! == "-112"
{
print("hello")
}
Error itself says it's different types Int and String.
You can need to typecast one or another in same form and them compare.
if (String(error?.code)!) == "-112"){
print("hello")
}
Swift is a language with a strong type system. You can compare only values of the same type.
Since the left side is Int anyway use an Int value for the right side. Creating a string is unnecessarily expensive. Don’t do that.
The most efficient (and safe) solution is
if error?.code == -112
{
print("hello")
}
You need to type-cast your error code result to a string, like so:
if String(error?.code)!) == "-112" {
print("Hello")
}
Essentially, you are taking the error?.code, "casting" it as a string by placing it in a string "container mould" and unwrapping the value (retrieving the casted result).
In addition, if you are working with an API response, you have to account for all other error codes in the else/if statement to make sure all responses are handled properly (just in case you are).
I'm trying to update some of my swift code to comply with the swift 2.2 guide lines. I'm trying to update my for loops this is what I have currently
for(var i = 0; persons?.count > i; i += 1){}
and this is what I thought I should be using
for i in (0..<persons?.count){}
But I'm getting this error "Binary operator '..<' cannot be applied to operands of type 'Int' and 'Int?'"
I'm just not sure what I'm missing.
The problem is that persons?.count might be nil and 0..<nil doesn't make any sense. you can easily fix this by using nil coalescing though:
for i in 0..<(persons?.count ?? 0) {
doStuff(i)
}
Or if you prefer you could overload the ..< operator to accept an optional as its second argument:
func ..<<T:ForwardIndexType where T:Comparable>(lower: T, upper: T?) -> Range<T> {
return lower..<(upper ?? lower)
}
This allows you to just write:
for i in 0..<persons?.count {
doStuff(i)
}
As Sulthan points out in the comments, this is probably not the best solution for your problem though. You should likely handle the case of persons being nil earlier in your code:
guard let persons = persons else {
// take care of business
}
for person in persons {
doStuff(person)
}
I am using a 3rd party C library in my iOS application, which I am in the process of converting from Objective-C to Swift. I hit an obstacle when attempting to read one of the structs returned by the C library in Swift.
The struct looks similar to this:
typedef unsigned int LibUint;
typedef unsigned char LibUint8;
typedef struct RequestConfiguration_ {
LibUint8 names[30][128];
LibUint numberNames;
LibUint currentName;
} RequestConfiguration;
Which is imported into Swift as a Tuple containing 30 Tuples of 128 LibUint8 values. After a long time of trial and error using nested withUnsafePointer calls, I eventually began searching for solutions to iterating a Tuple in Swift.
What I ended up using is the following functions:
/**
* Perform iterator on every children of the type using reflection
*/
func iterateChildren<T>(reflectable: T, #noescape iterator: (String?, Any) -> Void) {
let mirror = Mirror(reflecting: reflectable)
for i in mirror.children {
iterator(i.label, i.value)
}
}
/**
* Returns a String containing the characters within the Tuple
*/
func libUint8TupleToString<T>(tuple: T) -> String {
var result = [CChar]()
let mirror = Mirror(reflecting: tuple)
for child in mirror.children {
let char = CChar(child.value as! LibUint8)
result.append(char)
// Null reached, skip the rest.
if char == 0 {
break;
}
}
// Always null terminate; faster than checking if last is null.
result.append(CChar(0))
return String.fromCString(result) ?? ""
}
/**
* Returns an array of Strings by decoding characters within the Tuple
*/
func libUint8StringsInTuple<T>(tuple: T, length: Int = 0) -> [String] {
var idx = 0
var strings = [String]()
iterateChildren(tuple) { (label, value) in
guard length > 0 && idx < length else { return }
let str = libUint8TupleToString(value)
strings.append(str)
idx++
}
return strings
}
Usage
func handleConfiguration(config: RequestConfiguration) {
// Declaration types are added for clarity
let names: [String] = libUint8StringsInTuple(config.names, config.numberNames)
let currentName: String = names[config.currentName]
}
My solution uses reflection to iterate the first Tuple, and reflection to iterate the second, because I was getting incorrect strings when using withUnsafePointer for the nested Tuples, which I assume is due to signage. Surely there must be a way to read the C strings in the array, using an UnsafePointer alike withUsafePointer(&struct.cstring) { String.fromCString(UnsafePointer($0)) }.
To be clear, I'm looking for the fastest way to read these C strings in Swift, even if that involves using Reflection.
Here is a possible solution:
func handleConfiguration(var config: RequestConfiguration) {
let numStrings = Int(config.numberNames)
let lenStrings = sizeofValue(config.names.0)
let names = (0 ..< numStrings).map { idx in
withUnsafePointer(&config.names) {
String.fromCString(UnsafePointer<CChar>($0) + idx * lenStrings) ?? ""
}
}
let currentName = names[Int(config.currentName)]
print(names, currentName)
}
It uses the fact that
LibUint8 names[30][128];
are 30*128 contiguous bytes in memory. withUnsafePointer(&config.names)
calls the closure with $0 as a pointer to the start of that
memory location, and
UnsafePointer<CChar>($0) + idx * lenStrings
is a pointer to the start of the idx-th subarray. The above code requires
that each subarray contains a NUL-terminated UTF-8 string.
The solution suggested by Martin R looks good to me and, as far as I can see from my limited testing, does work. However, as Martin pointed out, it requires that the strings be NUL-terminated UTF-8. Here are two more possible approaches. These follow the principle of handling the complexity of C data structures in C instead of dealing with it in Swift. Which of these approaches you choose depends on what specifically you are doing with RequestConfiguration in your app. If you are not comfortable programming in C, then a pure Swift approach, like the one suggested by Martin, might be a better choice.
For the purposes of this discussion, we will assume that the 3rd party C library has the following function for retrieving RequestConfiguration:
const RequestConfiguration * getConfig();
Approach 1: Make the RequestConfiguration object available to your Swift code, but extract names from it using the following C helper function:
const unsigned char * getNameFromConfig(const RequestConfiguration * rc, unsigned int nameIdx)
{
return rc->names[nameIdx];
}
Both this function's signature and the RequestConfiguration type must be available to the Swift code via the bridging header. You can then do something like this in Swift:
var cfg : UnsafePointer<RequestConfiguration> = getConfig()
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig(cfg, cfg.memory.currentName)))
{
print(s)
}
This approach is nice if you need the RequestConfiguration object available to Swift in order to check the number of names in multiple places, for example.
Approach 2: You just need to be able to get the name at a given position. In this case the RequestConfiguration type does not even need to be visible to Swift. You can write a helper C function like this:
const unsigned char * getNameFromConfig1(unsigned int idx)
{
const RequestConfiguration * p = getConfig();
return p->names[idx];
}
and use it in Swift as follows:
if let s = String.fromCString(UnsafePointer<CChar>(getNameFromConfig1(2)))
{
print(s)
}
This will print the name at position 2 (counting from 0). Of course, with this approach you might also want to have C helpers that return the count of names as well as the current name index.
Again, with these 2 approaches it is assumed the strings are NUL-terminated UTF-8. There are other approaches possible, these are just examples.
Also please note that the above assumes that you access RequestConfiguration as read-only. If you also want to modify it and make the changes visible to the 3rd party library C code, then it's a different ballgame.
Given an array of string, I want to find the first one that can be successfully converted to a real without using exceptions.
The only relevant functions I can see in Phobos are std.conv.to and std.conv.parse, but both of these will throw an exception if they cannot convert the string. I'd like to avoid exceptions because this is not going to be an exceptional circumstance for my use case.
C# provides TryParse for exactly this. Is there anything similar in D?
(of course, I could parse the string myself to determine if it is convertible to real, but it's non-trivial so I'd like to avoid that if possible).
Phobos doesn’t appear to have a way to do this without exceptions, besides std.stream. The problem is that std.stream seems to be deprecated. Here is an example using sscanf with double, though I don’t know how to do it with real:
extern (C) int sscanf(const char* input, const char* format, ...);
auto tryParseDouble(string input) {
import std.string;
import std.typecons;
double result;
if (sscanf(input.toStringz, "%lf".toStringz, &result) == 1) {
return Nullable!double(result);
} else {
return Nullable!double();
}
}
void main() {
import std.algorithm;
import std.range;
import std.stdio;
auto myArray = ["foo", "bar", "3.14", "42"];
auto x = myArray
.map!(tryParseDouble)
.filter!(x => !x.isNull)
.front
.get;
writeln(x);
}
While sscanf() works, it is unsafe. I would open an enhancement request.
Try adapting the Phobos code, returning NaN instead of throwing.