swift: can I have a property thats actually a reference? - ios

for example.. I want to pass in some dictionaries into a class in its initializer, and i want to reference those dictionaries across my class.. the problem is when I set them as properties, they are actually being copied, not referenced.
example:
var activeDict: [Int: Projectile]
var inactiveDict: [Int: Projectile]
init(inout activeDict: [Int: Projectile], inout inactiveDict: [Int: Projectile]) {
self.activeDict = activeDict
self.inactiveDict = inactiveDict
I want to use activeDict, and inactiveDict across my class. I want them to be references of the originals that are being passed in.

You can store an UnsafeMutablePointer to the dictionary, here is an example, tested in playground:
var dict = ["hejj": 1]
class A<T> {
var myDictRef: UnsafeMutablePointer<T>
init(ref: UnsafeMutablePointer<T>) {
self.myDictRef = ref
}
}
let a = A(ref: &dict)
a.myDictRef.memory["asd"] = 3
a.myDictRef.memory
dict
Updated
In your case use it like that:
var activeDict: UnsafeMutablePointer<[Int: Projectile]>
var inactiveDict: UnsafeMutablePointer<[Int: Projectile]>
init(activeDict: UnsafeMutablePointer<[Int: Projectile]>, inactiveDict: UnsafeMutablePointer<[Int: Projectile]>) {
self.activeDict = activeDict
self.inactiveDict = inactiveDict
}
whenever you want to use activeDict or inactiveDict, you can call the dictionary behind the pointer with their memory property like:
activeDict.memory[YourKey] = YourValue

Related

2 arrays into one dictionary while maintaining the indexes

I have two separate arrays that I want to import into a dictionary. Order is extremely important because both arrays must match in index
struct MyVariables {
static var users:NSArray!
static var img:NSArray!
}
var data = SearchVC.getData()
MyVariables.users = data.users; //array 1 (key)
MyVariables.img = data.img; //array 2
// Goal is to insert these arrays into a dictionary while maintaing the matching indexes on both arrays
// Dictonary (MyVariables.img, key: MyVariables.users)
A Dictionary does not have a particular order. However, if both arrays have the same length, it is quite easy to iterate over them together:
var dictionary = [NSString: AnyObject]()
for var index = 0; index < data.users.count; index++ {
let img = data.img as! NSString
dictionary[img] = data.users[index]
}
Or, as #robertvojta suggested, use the zip() method:
var dictionary = [NSString: AnyObject]()
for (user, image) in zip(data.users, data.img) {
let img = image as! NSString
dictionary[img] = user
}
The key in a dictionary in swift must be hashable. i.e., not AnyObject.
Assuming you can replace some of your untyped Swift arrays, or cast them like so:
struct MyVariables {
var users:Array<AnyObject>
var img:Array<String>
}
then you can iterate through 1 array using a preferred Swift method and access the second using indexing:
var dictionary = Dictionary<String, AnyObject>()
for (index, element) in enumerate(MyVariables.img) {
dictionary[element] = MyVariables.users[index]
}
Use for loop for travels the array in that as per index access keys and values respective array and add it in dictionary. Its so simple so you can achive your goal using it.
I hope it will help you!

Passing String array to a function

I am trying to pass an array to a function:
var array:[String] = []
// fill the array
array.append(uniqueId as String)
// pass the array to a function:
GamePrefrences.setLevelsArray(array)
My function is declares like this:
func setLevelsArray(arr:[String])
{
GamePrefrences.levels_array = arr
}
But on the line i try to call the function it gives with an error:
cannot invoke ... with argument list of type [(String)]
What is the problem? if its possible to provide brief explanation
First of all, your function is not a class level function and you are calling the method directly using class name.
Try like this.
var array:[String] = []
// fill the array
array.append(uniqueId as! String)
// pass the array to a function:
GamePrefrences.setLevelsArray(array)
Function declaration.
class func setLevelsArray(arr:[String])
{
GamePrefrences.levels_array = arr
}
or,
var array:[String] = []
// fill the array
array.append(uniqueId as String)
// pass the array to a function:
let instance = GamePrefrences()//Depends on you, how you defined the initialiser.
instance.setLevelsArray(array)
Your function body.
func setLevelsArray(arr:[String])
{
instance.levels_array = arr
}
please try something like this
func setLevelsArray(arr:[String])
{
let tempArr = arr
GamePrefrences.levels_array = tempArr
}
in Swift Arrays and Dictionary are passed by value not by reference, therefore if you are not changing the values or assigning to any other variable then Swift compiler does not get the copy, instead the variable still lives in the heap. so before assigning i believe it is necessary to copy this into another variable.
You have invalid declaration of an empty array. Here's how to declare empty array:
var array = [String]()

Swift: how to make array of mutable dictionaries? [duplicate]

I’m new to Swift and have been having some troubles figuring out some aspects of Arrays and Dictionaries.
I have an array of dictionaries, for which I have used Type Aliases - e.g.
typealias myDicts = Dictionary<String, Double>
var myArray : [myDicts] = [
["id":0,
"lat”:55.555555,
"lng”:-55.555555,
"distance":0],
["id":1,
"lat": 44.444444,
"lng”:-44.444444,
"distance":0]
]
I then want to iterate through the dictionaries in the array and change the “distance” key value. I did it like this:
for dict:myDicts in myArray {
dict["distance"] = 5
}
Or even specifically making sure 5 is a double with many different approaches including e.g.
for dict:myDicts in myArray {
let numberFive : Double = 5
dict["distance"] = numberFive
}
All my attempts cause an error:
#lvalue $T5' is not identical to '(String, Double)
It seems to be acting as if the Dictionaries inside were immutable “let” rather than “var”. So I randomly tried this:
for (var dict:myDicts) in myArray {
dict["distance"] = 5
}
This removes the error and the key is indeed assigned 5 within the for loop, but this doesn't seem to actually modify the array itself in the long run. What am I doing wrong?
The implicitly declared variable in a for-in loop in Swift is constant by default (let), that's why you can't modify it directly in the loop.
The for-in documentation has this:
for index in 1...5 {
println("\(index) times 5 is \(index * 5)")
}
In the example above, index is a constant whose value is automatically
set at the start of each iteration of the loop. As such, it does not
have to be declared before it is used. It is implicitly declared
simply by its inclusion in the loop declaration, without the need for
a let declaration keyword.
As you've discovered, you can make it a variable by explicitly declaring it with var. However, in this case, you're trying to modify a dictionary which is a struct and, therefore, a value type and it is copied on assignment. When you do dict["distance"] = 5 you're actually modifying a copy of the dictionary and not the original stored in the array.
You can still modify the dictionary in the array, you just have to do it directly by looping over the array by index:
for index in 0..<myArray.count {
myArray[index]["distance"] = 5
}
This way, you're sure to by modifying the original dictionary instead of a copy of it.
That being said, #matt's suggestion to use a custom class is usually the best route to take.
You're not doing anything wrong. That's how Swift works. You have two options:
Use NSMutableDictionary rather than a Swift dictionary.
Use a custom class instead of a dictionary. In a way this is a better solution anyway because it's what you should have been doing all along in a situation where all the dictionaries have the same structure.
The "custom class" I'm talking about would be a mere "value class", a bundle of properties. This was kind of a pain to make in Objective-C, but in Swift it's trivial, so I now do this a lot. The thing is that you can stick the class definition for your custom class anywhere; it doesn't need a file of its own, and of course in Swift you don't have the interface/implementation foo to grapple with, let alone memory management and other stuff. So this is just a few lines of code that you can stick right in with the code you've already got.
Here's an example from my own code:
class Model {
var task : NSURLSessionTask!
var im : UIImage!
var text : String!
var picurl : String!
}
We then have an array of Model and away we go.
So, in your example:
class MyDict : NSObject {
var id = 0.0
var lat = 0.0
var lng = 0.0
var distance = 0.0
}
var myArray = [MyDict]()
let d1 = MyDict()
d1.id = 0
d1.lat = 55.55
d1.lng = -55.55
d1.distance = 0
let d2 = MyDict()
d2.id = 0
d2.lat = 44.44
d2.lng = -44.44
d2.distance = 0
myArray = [d1,d2]
// now we come to the actual heart of the matter
for d in myArray {
d.distance = 5
}
println(myArray[0].distance) // it worked
println(myArray[1].distance) // it worked
Yes, the dictionary retrieved in the loop is immutable, hence you cannot change.
I'm afraid your last attempt just creates a mutable copy of it.
One possible workaround is to use NSMutableDictionary:
typealias myDicts = NSMutableDictionary
Have a class wrapper for the Swift dictionary or array.
class MyDictionary: NSObject {
var data : Dictionary<String,Any>!
init(_ data: Dictionary<String,Any>) {
self.data = data
}}
MyDictionary.data

What is the use of creating Constant (let) empty Array object?

In the Swift PDF file released by Apple i came thorough this code
To create an empty array or dictionary, use the initializer syntax.
let emptyArray = [String]()
let emptyDictionary = [String: Float]()
Here what is the use of creating a let (constant) object with empty array, where we cannot insert any values into it in next line ??!!
while teaching objective- c they start teaching like
NSArray *arrayObj = [[NSArray alloc] init]
if we declare like this we cannot add objects after initialisation
similarly they are teaching us how to initialise an array or dictionary objects
one more difference is if we allocate an empty array then we can assign another array with this.
let will not allow you to assign another array to it also
let emptyArray = [String]()
let/var filledArray = ["stack", "overflow"]
emptyArray = filledArray // will give you an error
Not much use, but the value can be copied:
let emptyDictionary = [String: Float]()
var otherDictionary = emptyDictionary
otherDictionary["a"] = 0.5
The property declaration sets them to a default, but you could actually change the value to something else in init. This would only be the case for class properties, not inline properties though.
Here's an example in a class scope where a let property can have a default but be changed:
class Whatever {
let testArray = [Int]()
init() {
testArray = [0,1,2]
}
}

Error trying to access members of Array of AnyObject within a Dictionary - Is there a way around unwrapping?

I have a dictionary set up as:
var jDict = Dictionary<String, AnyObject[]>()
Where the arrays are either a collection of custom buttons (JunkButton) or Labels (JunkLabels).
I am having an issue when trying to access the members of the arrays contained in the Dictionary as follows:
let thisArray = jDict[key]
var aButton = thisArray[0] //Gives error: 'AnyObject[]? does not have a member named 'subscript'
I can get around this by downcasting the whole array as follows:
if let aArray = thisArray as? JunkButton[]{
var aButton = aArray[0]
}
This seems very cumbersome especially if I am sure I know what type the array is made up of beforehand. Is there a way to cast thisArray when it is created that would allow me to extract its elements without unwrapping them each time?
Dictionary always give you Optional value.
Your code is like this
let thisArray : Optional<AnyObject[]> = jDict[key]
You need to unwrap it to get non-optional value
let thisArray = jDict[key]! // thisArray is AnyObject[]
You really shouldn't use a dictionary for this. Swift makes it very easy to use custom little structs or classes instead of dictionaries:
struct JunkItems {
var buttons: [JunkButton] = []
var labels: [JunkLabel] = []
}
Then you can access those items like this without downcasting:
for button in junkItems.buttons {
// ...
}
Or:
if let button = junkItems.buttons[0] {
// ...
}
Btw, the array notation [JunkButton] is new in beta 3.

Resources