Converting an Objective C array declaration to Swift - objective-c

How would I translate this Obj-C into Swift? I'm not sure about the new Swift 2 syntax and all.
unsigned char pixel[4] = {0};

According to the comments there seems to be an additional question about what the Objective-C code means: unsigned char pixel[4] declares pixel as an array of 4 unsigned char's. The = {0} initializes all elements of the array to 0.
Hence the simplest conceptual equivalent in Swift is:
var pixel: [UInt8] = [0,0,0,0]
Unlike C and Objective-C, Swift does not allow specifying the size of the array in advance and thus all four zeroes must be given to obtain the correct length - in C and Objective-C the extra zeroes can be omitted for brevity since it is already known that the array's size is 4.
Arguably you could use CUnsignedChar instead of UInt8 (as the unsigned char in C is not strictly guaranteed to be UInt8), but it is unnecessary unless you're going to be passing the values to a C function expecting unsigned char. In any case they are extremely likely to be the same type, and on the odd platforms where they aren't the same type it is more likely that the C code is actually wrong and used unsigned char where they meant uint8_t.

You can do it this way :
var pixel = [UInt8](count:4, repeatedValue:0)
Or :
var pixel:[UInt8] = [0,0,0,0]

Swift equivalent of unsigned char is CUnsignedChar
var pixel : [CUnsignedChar]()
You cannot give fixed length arrays in CMutablePointers in swift. So you have to declare like this. Reference
See this link to overcome this issue

Related

Convert unsinged char array from objective-c to UnsafeMutablePointer<UInt8> swift

I have an unsigned char array in .h file. and, also I have a function that takes unsigned char array as input. When I try to call this function in swift, it gets UnsafeMutablePointer<UInt8>. So, automatic objective-c to swift converter thinks unsigned char should be converted as UnsafeMutablePointer<UInt8>. But, I can not pass my variable to this function directly. Because I get,
Cannot convert value of type '(UInt8, UInt8, UInt8, UInt8, UInt8)' to expected argument type 'UnsafeMutablePointer<UInt8>!'
Length of this array is static. So, I can create
let key = UnsafeMutablePointer<UInt8>.allocate(capacity: 64);
and, also I can get value by KEY.0, KEY.1 ... etc. So, all I need is to create a for loop to read value from KEY and assign it to key
for index in 1...64 {
key[index] = KEY[index];
}
but, this gives compilation error as:
Value of tuple type '(UInt8, UInt8, UInt8, UInt8, UInt8)' has no member 'index'
so, first question, how I can get any value from KEY by index. Second is, is there any easier way to convert a unsigned char array to UnsafeMutablePointer<UInt8>
A C array
unsigned char ckey[64];
is imported as a tuple in Swift:
public var ckey: (UInt8, ..., UInt8)
and one cannot access the tuple elements by subscripting with an index.
(Well, you can when using Mirror).
However:
The address of a C array is the same as the address of the first
array element, and
for structures imported from C, Swift preserves the memory layout.
The latter was confirmed by Apple engineer Joe Groff:
... You can leave the struct defined in C and import it into Swift. Swift will respect C's layout.
Therefore you can pass the address of the first tuple element to
the function:
f(key: &ckey.0)
Of course – as in C – the information about the size of the array is
lost, so the array should be NUL-terminated, or f should know
about the array size. Alternatively, pass the size
as an additional argument to the function:
foo(key: &ckey.0, length: MemoryLayout.size(ofValue: ckey))

What is int foo[] = {1200,100} and how do I recreate it in Swift?

Testing out some third party objective-C code I see the following:
int beepData[] = {1200,100};
What am I looking at here? An int is being created from a pair of other integers? I've not seen this feature before.
I would also like to know how to create the same variable in Swift.
EDIT
I assumed this was returning an int, not an array. The code I'm reviewing looks like this:
int beepData[] = {1200,100};
[[DTDevices sharedDevice] barcodeSetScanBeep:TRUE volume:10 beepData:beepData length:sizeof(beepData) error:nil];
Where the method signature I am intending to pass the variable to is:
-(BOOL)barcodeSetScanBeep:(BOOL)enabled volume:(int)volume beepData:(int *)data length:(int)length error:(NSError **)error;
I guess the right question might have been - what is (int *) and how might I create one in Swift?
What am I looking at here?
That is an array of ints, with two elements.
[How can I] create the same variable in Swift?
The same variable in swift might be declared as:
var beepData : [Int] = [ 1200, 100 ]
You might find this answer about different ways to declare an array in C useful
What is (int *)
It's an int pointer, it points to the memory address of an int. Incrementing it would move along the memory addresses (in int-sized chunks) and point to the next bit of memory.
[1][3][5][4][2]
^
This little arrow represents an int*. Even though it currently points to 1,
incrementing it doesn't equal 2. In this case it would equal 3, the value of the int in the next block of memory.
[1][3][5][4][2]
^
How might I create one in Swift?
To be quite honest, I'm not sure if Swift has pointers in the normal sense. I've not used it a great deal. However, if you are porting that method, I'd probably give it an array of ints.
func barcodeSetScanBeep(enabled : Bool, volume : Int, beepData: [Int], length : Int, error : NSError)
That's a C array, declared with 1200 and 100 as the members of the array.
Its declared with the type, and a bracket with the size (or empty for compiler deduced size), such as int cArrayOfInts[] = blahblahblah.
Note how the members of the array can be primitives, instead of objects. This isn't possible in Objective-C.
To recreate this in swift, simply use var beepData = [1200, 100] and it will be type inferred to an array of Ints.
James already answered the particulars of your question - consider this some additional information.
Declarations in C are based on the types of expressions, not objects. If you have an array of integers and you want to access the i'th integer, you would write
x = arr[i];
The type of the expression arr[i] is int, so the declaration of arr is written as
int arr[N]; // arr is an N-element array of int
Similar logic applies to pointer declarations; if you have a pointer to a double and you want to access the pointed-to value, you'd write
y = *p;
The type of the expression *p is double, so the declaration of p is written as
double *p;
Same for function declarations; you call a function that returns an integer as
x = f();
The type of the expression f() is int, so the declaration of the function is written as
int f( void ); // void means the function takes no parameters
C declaration syntax uses something called a declarator to specify an object's array-ness, pointer-ness, or function-ness. For example:
int x, arr[10], *p, f(void);
declares x as a plain int, arr as a 10-element array of int, p as a pointer to an int, and f as function taking no parameters and returning int.
You'll occasionally see pointer declarations written as T* p, however they will be parsed as T (*p); the * is always part of the declarator, not the type specifier.
C declaration syntax allows you to create some pretty complex types in a compact format, such as
int *(*(*f[N])(void))[M];
In this declaration, f is an N-element array of pointers to functions returning pointers to M-element arrays of pointers to int.
In your declaration
int beepData[] = {1200, 100};
beepData is being declared as an array of an unknown size; the size is taken from the number of elements in the initializer {1200, 100}, in this case 2.
I know nothing about Swift, so I wouldn't know how to translate the C code to it. The best I can do is explain how the C code works.

2 dimensional C array as Objective C parameter, malloc incompatible with sizeof operand

I need to create a pointer to a 2 dimensional C array which will be passed as a parameter to a function later. This is what I am attempting:
int64_t (*results)[numSamples] = malloc(sizeof(int64_t[numSamples])*amountPossible);
The result I was hoping for is a pointer to a 2 dimensional array that would effectively be something like int64_t[amountPossible][numSamples], but using Analyze in Xcode I get the warning
Result of 'malloc' is converted to a pointer of type
'int64_t[numSamples]', which is incompatible with sizeof operand type
'int64_t[numSamples]'
numSamples will always be the same value, but amountPossible is variable. Is there a better way to do this?
This appears to be a bug in the analyzer. The only permutation I discovered which doesn't trip the analyzer is to break up the statement:
size_t bytes = sizeof(int64_t[numSamples]) * amountPossible;
int64_t (*results)[numSamples] = malloc(bytes);
Which shouldn't of course be required!
Report it as a bug to Apple.

Odd use of curly braces in C

Sorry for the simple question but I'm on vacation reading a book on core audio, and don't have my C or Objective C books with me...
What are the curly braces doing in this variable definition?
MyRecorder recorder = {0};
Assuming that MyRecorder is a struct, this sets every member to their respective representation of zero (0 for integers, NULL for pointers etc.).
Actually this also works on all other datatypes like int, double, pointers, arrays, nested structures, ..., everything you can imagine (thanks to pmg for pointing this out!)
UPDATE: A quote extracted from the website linked above, citing the final draft of C99:
[6.7.8.21] If there are fewer initializers in a brace-enclosed list
than there are elements or members of an aggregate, [...] the remainder of the
aggregate shall be initialized implicitly the same as objects that
have static storage duration.
Its initializing all members of recorder structure to 0 according to C99 standard. It might seem that it initializes every bit of the structure with 0 bits. But thats not true for every compiler.
See this example code,
#include<stdio.h>
struct s {
int i;
unsigned long l;
double d;
};
int main(){
struct s es = {0};
printf("%d\n", es.i);
printf("%lu\n", es.l);
printf("%f\n", es.d);
return 0;
}
This is the output.
$ ./a.out
0
0
0.000000
It is an initialization of a structure.
Actually, it don't initliaze all the elements of the structure, just the first one. But, the others are automatically initialized with 0 because this is what the C standard ask to do.
If you put:
MyRecorder recorder = {3};
The first element will be 3 and the others weill be 0.
MyRecorder could be one of the following and you are attempting to initialize all the elements of that with zero
typedef struct _MyRecorder1 {
int i;
int j;
int k;
}MyRecorder1;
typedef int MyRecorder2[3];
Unlike C++11, in C99 there has to be at least one element in initializer braces.
C++11 struct:
MyRecorder recorder{};
C struct:
MyRecorder recorder = {0};

Unfamiliar C syntax in Objective-C context

I am coming to Objective-C from C# without any intermediate knowledge of C. (Yes, yes, I will need to learn C at some point and I fully intend to.) In Apple's Certificate, Key, and Trust Services Programming Guide, there is the following code:
static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey\0";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey\0";
I have an NSString that I would like to use as an identifier here and for the life of me I can't figure out how to get that into this data structure. Searching through Google has been fruitless also. I looked at the NSString Class Reference and looked at the UTF8String and getCharacters methods but I couldn't get the product into the structure.
What's the simple, easy trick I'm missing?
Those are C strings: Arrays (not NSArrays, but C arrays) of characters. The last character is a NUL, with the numeric value 0.
“UInt8” is the CoreServices name for an unsigned octet, which (on Mac OS X) is the same as an unsigned char.
static means that the array is specific to this file (if it's in file scope) or persists across function calls (if it's inside a method or function body).
const means just what you'd guess: You cannot change the characters in these arrays.
\0 is a NUL, but including it explicitly in a "" literal as shown in those examples is redundant. A "" literal (without the #) is NUL-terminated anyway.
C doesn't specify an encoding. On Mac OS X, it's generally something ASCII-compatible, usually UTF-8.
To convert an NSString to a C-string, use UTF8String or cStringUsingEncoding:. To have the NSString extract the C string into a buffer, use getCString:maxLength:encoding:.
I think some people are missing the point here. Everyone has explained the two constant arrays that are being set up for the tags, but if you want to use an NSString, you can simply add it to the attribute dictionary as-is. You don't have to convert it to anything. For example:
NSString *publicTag = #"com.apple.sample.publickey";
NSString *privateTag = #"com.apple.sample.privatekey";
The rest of the example stays exactly the same. In this case, there is no need for the C string literals at all.
Obtaining a char* (C string) from an NSString isn't the tricky part. (BTW, I'd also suggest UTF8String, it's much simpler.) The Apple-supplied code works because it's assigning a C string literal to the static const array variables. Assigning the result of a function or method call to a const will probably not work.
I recently answered an SO question about defining a constant in Objective-C, which should help your situation. You may have to compromise by getting rid of the const modifier. If it's declared static, you at least know that nobody outside the compilation unit where it's declared can reference it, so just make sure you don't let a reference to it "escape" such that other code could modify it via a pointer, etc.
However, as #Jason points out, you may not even need to convert it to a char* at all. The sample code creates an NSData object for each of these strings. You could just do something like this within the code (replacing steps 1 and 3):
NSData* publicTag = [#"com.apple.sample.publickey" dataUsingEncoding:NSUnicodeStringEncoding];
NSData* privateTag = [#"com.apple.sample.privatekey" dataUsingEncoding:NSUnicodeStringEncoding];
That sure seems easier to me than dealing with the C arrays if you already have an NSString.
try this
NSString *newString = #"This is a test string.";
char *theString;
theString = [newString cStringWithEncoding:[NSString defaultCStringEncoding]];