"Extract" array from dictionary in swift - ios

I'm pretty new to Swift and need your help on a (probably) pretty basic problem.
I have a dictionairy:
var dict = ["title" : "Title", "Features" : ["feat1", "feat2", "feat3"], ...]
I can create a string from it like so:
var headline = dict["title"]! as string
but I couldn't manage to create an array. I tried in various combinations:
var features = dict["Features"]
var features = dict["Features"]! as Array
var features: Array = dict["Features"]
So please enlighten me! How do create an array? Is it possible at all?

You should specify the type for the array. Either
let features = dict["Features"] as [String]
or
let features = dict["Features"] as Array<String>
See the discussion of collection types in The Swift Language.

Your problem is that you don't have a type for the array. You describe the type of an array in swift by putting the type name in brackets. In your case, this will be [String]. Thus, your code should be var features = dict["Features"] as [String] for a mutable array, or use let for an immutable array. Hope this helps.

Related

how to initialize array in swift

I am completely new in swift and iOS developing.
I want to initialize this array
I defined the array like this when my class starts
var i = 0
var ArrayTitle = [NSString]()
and then I need to initialize it in one of the functions like this
let ArrayTitl[i] = "text"
and I checked it even like this but the error is same
let ArrayTitl[0] = "text"
but it has this Error
Cannot assign to immutable expression of type '[Int]'
Appreciate any help. thanks
You are using a dynamic array so you need to append the value.
Here's a small exemple:
var arrayTitle = [String]()
arrayTitle.append("text")
print(arrayTitle[0]);

iOS cannot convert [String:Any?] to [String] How to convert?

I'm rushing a project and am not able to research to find the answer. I hope I can get some help on this.
var tt: Array<[String:Any]> = []
var forpickarray: [String] = []
Error: cannot convert [String:Any?] to [String]
for index in 1...self.tt.count {
var arr: [String] = self.tt[index-1]
forpickarray.append(self.tt[index-1])
}
I am trying to get the value- Just the listname
[["total": 2, "listName": Testing, "listid": 1], ["total": 1, "listName": Yeeea, "listid": 2]]
Oh, just seen your edit. Helps a lot.
To get the value of the listName from each dictionary you can do like this...
forPickArray = tt.flatMap { $0["listName"] }
Rename your variables to have sensible names. tt is not a sensible name. I have no idea what it is :D
within your for-loop, are you trying to extract keys from the dictionary and convert it to an array? then you need to do the following:
var arr: [String] = Array(tt[index-1].keys)
forpickarray.append(contentsOf: arr)
Because tt is an array of dictionary, each element in tt could have many keys
Please use native Swift syntax rather than ugly Objective-cish code.
A loop is not needed at all:
forpickarray = tt.flatMap{ $0["listName"] as? String }
Even if a loop was required there is a much more efficient way than a (zero!)index-based for loop:
for item in tt {
forpickarray.append(item)
}

"Empty collection literal requires an explicit type" error on Swift3

I have a variable on my class:
var list = []
and I use it on a function of my class:
func chargeData (data: NSArray){
list = data
}
It worked well on my project in Swift 2.3 but when I have updated it to XCode8 and Swift3 it gives to me the following error:
Empty collection literal requires an explicit type
so I have added a typecast to my list variable:
var list = [] as! NSArray
but it gives to me the following alert:
Forced cast of 'NSArray' to same type has no effect
I know that an alert does not broke the application but I would like to solve this error in a proper way.
Did someone got the same error and solved it properly?
Thanks in advance!
This error occurs since implicit conversions are abolished so you have to tell the compiler the explicit type (of the ArrayLiteral []):
var list: NSArray = []
// or
var list = [] as NSArray
The Swift 5 guided tour is pretty explicit about creating empty arrays or dictionaries: https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html#ID461 towards the end of the first section.
To create an empty array or dictionary, use the initializer syntax.
let emptyArray = [String]()
let emptyDictionary = [String: Float]()
Update swift 4 :
var array = [] as [String]
You are mixing ObjectiveC (NSArray) and Swift (Array<T>). Items inside an NSArray are assumed to be NSObject and its subclasses, while Swift has no clue what T is since the array is empty and hence type inference doesn't work.
If you declare it like this:
var data: NSArray = []
there will be a conflict since var means mutable in Swift, but NSArray is immutable in ObjC. You can get around that by changing it to NSMutableArray, which is a subclass of NSArray:
let data = NSMutableArray() // note that we don't need var here
// as NSMutableArray is already mutable
If you want to keep data as Swift's Array, give it a type:
var data = [MyDataModel]()
// or
var data = [AnyObject]()
// usage:
chargeData(data: data as NSArray)

Comparing two arrays in swift and removing elements with specific fields that don't match

I have two arrays:
var packages = [SAPackage]()
var inappProducts = [SKProduct]()
The SAPackage object in the packages array has a String var titled sku. TheSKProduct object in the inappProducts array has a String var titled productIdentifier. What I want to do is remove any object in the packages array that doesn't have a sku String that matches any objects productIdentifier String in the inappProducts array. Is there anyway to go about this? Thought about using sets to find an intersection however I cannot examine individual object fields doing this just whole objects. Any pointers on this would be greatly appreciated!
You can use this code to filter those packages whose "sku" exist in inappProducts, SKProducts,
let filteredPackages = packages.filter { package in
return inappProducts.contains { product in
product.productIdentifier == package.sku
}
}
You can use the filter function of Swift.
Here a simple example:
let dic1 = ["bear","cat","dog","fish"]
let dic2 = ["horse","cat","dog","bird"]
let f = dic1.filter{dic2.contains($0)}
// ["cat", "dog"]

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

Resources