Swift multidimensional array - ios

I'm working on a piece of code that use generics. This is an example of what I'm trying to achieve :
var strings: Array<Array<String>> = [["1", "2", "3"], ["4", "5", "6"]]
var array: Array<Array<AnyObject>> = strings
But the compiler says "'String' is not identical to 'AnyObject'".
I have no idea why the compiler complains and how to achieve what I need.
I already tried casting it like this :
var array: Array<Array<AnyObject>> = strings as Array<Array<AnyObject>>
Without any success.
Do you guys have any idea ?
Thanks.

That doesn't work because, as the compiler says, AnyObject is not String, although you can cast AnyObject to String and vice versa.
It doesn't even work using different value types that may seem "compatible":
var array1: Array<Array<UInt>> = []
var array2: Array<Array<Int>> = array1
The only way to do what you need is to write a converter that given an array containing object of type String returns an array of AnyObject.
The reason is that even if 2 data types are compatible, they do not use the same amount of memory and can have different data members and initialization constraints.
Taking into account that arrays are value types, the assignment is not done by reference - instead a copy of the array is created and assigned to the destination variable. If the underlying data type is the same for left and right side of the assignment, each item in the array can just be copied byte by byte to create a copy of it. If the left and right side have different types, that is not possible because most likely they use memory in a different way (i.e. they may have different data members), so in that case the object should be instantiated via an initializer, but which one and using which parameters?

Related

Converting a slice to an array

I have a slice that I have guaranteed (in runtime) that its length is at least 8. I want to convert that slice to an array because I need to use std.mem.bytesAsValue() in order to create an f64 from raw bytes (for context, I'm implementing a binary serialization format).
I solved it like this, but I'd like to know if there is a better syntax for achieving the same goal:
var array: [8]u8 = undefined;
array[0] = slice[0];
array[1] = slice[1];
array[2] = slice[2];
array[3] = slice[3];
array[4] = slice[4];
array[5] = slice[5];
array[6] = slice[6];
array[7] = slice[7];
Given your goal, if alignment works out, you could just cast the slice pointer to a pointer to a f64: #ptrCast(*f64, slice.ptr). This saves you from even having to copy anything, in case you don't need to do that at all.
Note that bytesAsValues is a stdlib function that uses compiler builtins, if the signature doesn't match your needs, you can just skip it and use directly the builtins, like I mentioned above. Don't be afraid to read the stdlib source code.
Here's a godbolt link with some examples on how to do the conversion in-place (by casting the pointer) and by copying everything immediately as a float: https://zig.godbolt.org/z/3Y9o5zvfe
you can do this by std.mem.copy
var array = slice[0..8].*;
or using std.mem.copy
std.mem.copy(u8, &array, slice[0..2]);
while i think you can just need to put slice[0..8] as argument instead creating a variable

Dart - Pass by value for int but reference for list?

In Dart, looking at the code below, does it 'pass by reference' for list and 'pass by value' for integers? If that's the case, what type of data will be passed by reference/value? If that isn't the case, what's the issue that causes such output?
void main() {
var foo = ['a','b'];
var bar = foo;
bar.add('c');
print(aoo); // [a, b, c]
print(bar); // [a, b, c]
var a = 3;
int b = a;
b += 2;
print(a); // 3
print(b); // 5
}
The question your asking can be answered by looking at the difference between a value and a reference type.
Dart like almost every other programming langue makes a distinction between the two. The reason for this is that you divide memory into the so called stack and the heap. The stack is fast but very limited so it cannot hold that much data. (By the way, if you have too much data stored in the stack you will get a Stack Overflow exception which is where the name of this site comes from ;) ). The heap on the other hand is slower but can hold nearly infinite data.
This is why you have value and reference types. The value types are all your primitive data types (in Dart all the data type that are written small like int, bool, double and so on). Their values are small enough to be stored directly in the stack. On the other hand you have all the other data types that may potentially be much bigger so they cannot be stored in the stack. This is why all the other so called reference types are basically stored in the heap and only an address or a reference is stored in the stack.
So when you are setting the reference type bar to foo you're essentially just copying the storage address from bar to foo. Therefore if you change the data stored under that reference it seems like your changing both values because both have the same reference. In contrast when you say b = a your not transferring the reference but the actual value instead so it is not effected if you make any changes to the original value.
I really hope I could help answering your question :)
In Dart, all type are reference types. All parameters are passed by value. The "value" of a reference type is its reference. (That's why it's possible to have two variables containing the "same object" - there is only one object, but both variables contain references to that object). You never ever make a copy of an object just by passing the reference around.
Dart does not have "pass by reference" where you pass a variable as an argument (so the called function can change the value bound to the variable, like C#'s ref parameters).
Dart does not have primitive types, at all. However (big caveat), numbers are always (pretending to be) canonicalized, so there is only ever one 1 object in the program. You can't create a different 1 object. In a way it acts similarly to other languages' primitive types, but it isn't one. You can use int as a type argument to List<int>, unlike in Java where you need to do List<Integer>, you can ask about the identity of an int like identical(1, 2), and you can call methods on integers like 1.hashCode.
If you want to clone or copy a list
var foo = ['a', 'b'];
var bar = [...foo];
bar.add('c');
print(bar); // [a, b, c]
print(foo); // [a, b]
var bar_two = []; //or init an empty list
bar_two.addAll([...bar]);
print(bar_two); // [a, b, c]
Reference link
Clone a List, Map or Set in Dart

How to match the 2d array datatype between swift and objective-c?

I am calling a .mm (objective-c / c++) class method from my swift viewController via linked headers. They are successfully linked. However, I am struggling to pass correct data types that match as parameters.
Here is where I call the function in swift
OpenCVWrapper.thefunc(array1, otherstuff);
...array1 is of type [[Int]]
and here is the definition in objective-c
+(NSString*) thefunc: (int[][2])array1 otherstuff(int)other{
but i get the error
Cannot convert value of type '[[Int]]' to expected argument type 'UnsafeMutablepointer<(Int32)(Int32)>!'
My question is, how can I match the data types so they both handle a basic 2D array of type Int?
UPDATE:
value / structure issues:
structure passed from swift:
structure received in OC:
First of all, you may need to know that C-array and Swift Array are different things. C-array represents a contiguous region of memory and uses the pointer to the first element when passed.
Second, if you want to use imported Objective-C method from Swift, you'd better check the generated header of the method.
(Press the "four square icon" and choose "Generated Interface" while editor is showing the .h file.)
Tested with a small sample project, your method is imported as:
open class func thefunc(_ array1: UnsafeMutablePointer<(Int32, Int32)>!, otherstuff other: Int32) -> String!
(The corresponding type to int in Swift is Int32, not Int.)
So, you may need to pass a mutable pointer to tuple (Int32, Int32), to do that you need to declare a Swift Array of Element type (Int32, Int32) and pass it as an inout argument (using &).
So, you may need to write something like this:
//Assuming all inner Array of `array1` have two elements.
var convertedArray = array1.map {(Int32($0[0]), Int32($0[1]))}
MyClass.thefunc(&convertedArray, otherstuff: someInt32Value)
But the conversion of huge array may take some amount of time, in some cases, which is critical.
You may declare your Swift side array1 as Array of (Int32, Int32) and modify other parts according to this change, and use it as:
//Somewhere in your code...
var array1: [(Int32, Int32)] = []
//...
//And call `thefunc` as:
MyClass.thefunc(&array1, otherstuff: someInt32Value)

Optional properties in optional classes VS Optional values in optional dictionaries

I noticed some interesting behavior when trying to access values of optional properties in optional classes VS trying to access the values of optional values in optional dictionaires.
It seems that in the former case you only need to unwrap once to access the value. However, in the latter case you have to unwrap twice to access the value. I was wondering why this is, and was hoping someone could provide me with some insight!
Below is an example accessing the value of an optional property in an optional class
class Cat{
var food : Food?
}
class Food{
var amount : Int?
}
var meowzer = Cat()
meowzer.food = Food()
meowzer.food?.amount = 10
var catFoodAmt = meowzer.food?.amount
print("\(catFoodAmt)")
if let catFoodCount = meowzer.food?.amount{
print("\(catFoodCount)")
}
The result of the first print statement is:
Optional(10)
The result of the second print statement (after unwrapping) is:
10
Below is an example of accessing the value of an optional value in an optional dictionary
var dog : [String : Int?]?
dog = ["treat_count" : 10]
var dogTreatAmt = dog?["treat_count"]
print("\(dogTreatAmt)")
if let dogTreatCount = dog?["treat_count"] , dogTreatCountFinal = dogTreatCount{
print("\(dogTreatCount)")
print("\(dogTreatCountFinal)")
}
The result of the first print statement is:
Optional(Optional(10))
The result of the second print statement (after unwrapping once) is:
Optional(10)
The result of the third print statement (after unwrapping twice) is:
10
Why do I need to unwrap twice to access the desired value in the second case but not the first?
My guess is it has to do with that fact that if I were to have used a key other than "treat_count" (like "count" for example) then the value for that key would have been nil. However, I haven't been able to find a iOS "rule" or a better explanation on why this is. Any help would be much appreciated.
The difference is that Cat.food?.amount returns Int? while Dictionary<String, Int?>.subscript(String) returns Int??.
This is because Dictionary.subscript<Key> returns Element?, and Element here is Int?. Thus you're getting one extra level of Optional.
Optional chaining just removes an extra Optional wrapping at the point that it's used. It doesn't collapse all Optionals. In one case you have two, collapsed to 1 (for one ?) and in the second you have three, collapsed to 2 (for one ?).
As vadian suggests, this would be a crazy Dictionary, so it's unlikely to come up in good Swift, but it can be reasoned about. If it weren't like this, you would lose information.
It actually makes sense : simply count the number of ?s :).
With you first example, the property is an optional where, in your second example, you have an optional dictionary where its key is a string and the value is an optional integer.
So if you want to access the value of the second example, you have to unwrap the dictionary, then unwrap whatever there is in that dictionary for a given key.
This is a good question. Let's think the type definition of a Dictionary:
struct Dictionary<Key : Hashable, Value>
And the signature of the subscript function:
public subscript (key: Key) -> Value?
Which can also be thought of as:
public subscript (key: Key) -> Optional<Value>
Armed with this, let's look at your dictionary, which is typed as:
Dictionary<String, Int?>
Or more explicitly
Dictionary<String, Optional<Int>>
Where Value is of type Optional<Int>, and Key is of type String
So if we substitute in the key, the subscript definition is:
subscript (key: String) -> Optional<Value>
And if we substitute it in the Value, we get what you are seeing:
subscript (key: String) -> Optional<Optional<Int>
Now, let's break down your code and to make everything fit together:
var dogTreatAmt = dog?["treat_count"]
Since dog is optional, no matter what you call on it, the result will also be wrapped in an Optional, which we will temporarily think of as Optional(FunctionReturn)
Now let's take a look at FunctionReturn, which is the subscript function. We have already determined that this will return Optional<Optional<Int>>
Which means that really you're returning Optional<Optional<Optional<Int>>>, however as noted by Rob Napier,
"Optional chaining removes an extra Optional wrapping at the point that it's used".

Listbox code from As Variant to As Long

I've learned that the As Long is much better than As Variant when it come to improving macro speed.
Dim data1() As Variant
data1 = Array("a", "b", "c", "d", "e")
Sheet1.ListBox1.List = data1
When I replace with As Long, my code doesn't work any more.
Your array doesn't contain Longs, it contains Strings. Try Dim data1() As String. (Don't worry - it's probably still faster than As Variant.)
While using explicit types is usually (almost always) better. This case is an exception because the List property of the ListBox is a Variant array anyway, so assigning a String or Long array to it causes an implicit type cast, so isn't any faster (and may even be slower).
What may make the difference is how you are loading data into the array before assigning it to the ListBox. If thats more efficient use explicit typed arrays then fine, use it.
BTW
Dim data1() as long
data1 = Array(1, 2, 3, 4, 5)
doesn't work because Array(...) returns a Varaint array which can't be assigned to an explicit typed array.

Resources