How to make array of UILabels in swift 3 - arrays

I tried this but got error !!!!
var lable : UILabel = [lable1, lable2, lable3]
// do stuff with label

In Swift, variable declarations follow this pattern:
var variable name: type = expression
You are saying that the type is a UILabel, while assigning it a list of UILabels.
Use [UILabel] as your type to fix your issue.

Two issues:
The type is UILabel (typo)
An array is indicated with a pair or square brackets []
However the compiler can infer the type (and the variable is most likely a constant)
let lables = [lable1, lable2, lable3]

if you want mutable :
var labels = [xyz1, xyz2, xyz2]
and if you want immutable
let labels = [xyz1, xyz2, xyz3]

Related

SWIFT: assigning all values of an item in a structure array to a variable

Sorry, I don't even have an idea of the keywords to search for answer.
I want to store all items within a global structure to a local variable.
struct HighScores: Codable {
var highscoreRecord: [HighscoreRecord]
}
struct HighscoreRecord: Codable {
var Rank:Int
var Date:Date
var avDuration:Float
var Score:Int
}
A global variable is based on this structure and populated within a UIViewController
var jsonResult: HighScores?
Now, in another UIViewController, I want to extract the values of Score for all Highscores and store it to a local variable. I thought it should look somewhat like this, however, I do not get it to work
#IBDesignable class ScoreTimeGraphView: UIView {
var graphScore = jsonResult!.highscoreRecord.Score
The declaration above throws "Value of type '[HighscoreRecord]' has no member 'Score'"
Any ideas how to do this?
Cheers!
highscoreRecord is an Array. You can't use .Score directly on it because the Array type doesn't have a property named Score.
However, because it's element type is HighScore (which does have the property you want), you can iterate over it and collect the Score property from each one.
I think this is what you are after:
var allGraphScores = jsonResult!.highscoreRecord.map { $0.Score }
.map(_:) takes a closure with one parameter, and passes in each element of a sequence in turn.
So, highscoreRecord.map { $0.Score } returns a new array, by finding the Score property of each HighScoreRecord in the array highscoreRecord.
PS it's probably a good idea to name your variables using lowercase camelCase, for readability and instant recognition by any Swift dev that Score is a variable and not an object.
You're trying to access the property from an array. You need to provide an index to remove the error. Update this line:
var graphScore = jsonResult!.highscoreRecord.Score
To this:
var graphScore = jsonResult!.highscoreRecord[0].Score

How to simplify Swift array initialization

This is in reference to https://stackoverflow.com/a/47765972/8833459.
The following statement is given:
let fooPaths: [WritableKeyPathApplicator<Foo>] = [WritableKeyPathApplicator(\Foo.bar), WritableKeyPathApplicator(\Foo.baz)]
Is there an init or something else that can be done so that the following (or something similar) might also work?
let fooPaths: [WritableKeyPathApplicator<Foo>] = [\Foo.bar, \Foo.baz]
The original statement is just too much typing! My "preferred" method currently gives the error:
error: cannot convert value of type 'WritableKeyPath<Foo, String>' to expected element type 'WritableKeyPathApplicator<Foo>'
The type is unnecessary:
let fooPaths = [WritableKeyPathApplicator(\Foo.bar), WritableKeyPathApplicator(\Foo.baz)]
The second Foo is unnecessary.
let fooPaths = [WritableKeyPathApplicator(\Foo.bar), WritableKeyPathApplicator(\.baz)]
Also the first one if you do provide the type:
let fooPaths: [WritableKeyPathApplicator<Foo>] = [WritableKeyPathApplicator(\.bar),
WritableKeyPathApplicator(\.baz)]
If the major concern is typing, add a local typealias:
typealias WKPA<T> = WritableKeyPathApplicator<T>
let fooPaths: [WKPA<Foo>] = [WKPA(\.bar),
WKPA(\.baz)]

Simple swift array append not working

I know this is going to be super elementary, but I have this piece of code:
var labels: [String]?
func initVC(image: Images){
self.image = image
let tempLabels = image.label?.allObjects as! [Labels]
for i in 0..<tempLabels.count{
labels?.append(tempLabels[i].label!)
}
}
labels is in the public scope, so the function should have access to it, but when the loop runs through, labels is still nil with no elements.
When I po during debugging, tempLabels is as I expect it to be with 2 string elements.
I'm pretty sure this is a very simple problem, but I guess I'm just out of it right now.
Labels has never been initialised. Change
var labels:[String]?
to
var labels:[String] = []
You are declaring the labels variable but never allowing it to store information. This means that it does not necessarily exist, since it is not initialized, and therefore cannot be used.
For it to be useable, you must initialize it
var labels:[String] = []
Yep, it was super simple.
Changed
var labels: [String]?
To
var labels = [String]()

Swift Dictionary: Get values as array

I have a dictionary containing UIColor objects hashed by an enum value, ColorScheme:
var colorsForColorScheme: [ColorScheme : UIColor] = ...
I would like to be able to extract an array of all the colors (the values) contained by this dictionary. I thought I could use the values property, as is used when iterating over dictionary values (for value in dictionary.values {...}), but this returns an error:
let colors: [UIColor] = colorsForColorSchemes.values
~~~~~~~~~~~~~~~~~~~~~^~~~~~~
'LazyBidrectionalCollection<MapCollectionView<Dictionary<ColorScheme, UIColor>, UIColor>>' is not convertible to 'UIColor'
It seems that rather than returning an Array of values, the values method returns a more abstract collection type. Is there a way to get an Array containing the dictionary's values without extracting them in a for-in loop?
As of Swift 2.0, Dictionary’s values property now returns a LazyMapCollection instead of a LazyBidirectionalCollection. The Array type knows how to initialise itself using this abstract collection type:
let colors = Array(colorsForColorSchemes.values)
Swift's type inference already knows that these values are UIColor objects, so no type casting is required, which is nice!
You can map dictionary to an array of values:
let colors = colorsForColorScheme.map { $0.1 }
Closure takes a key-value tuple from dictionary and returns just a value. So, map function produces an array of values.
More readable version of the same code:
let colors = colorsForColorScheme.map { (scheme, color) in
return color
}
UPDATE
From Xcode 9.0, dictionary values can be accessed using values property, which conforms to Collection protocol:
let colors = colorsForColorScheme.values
Typically you just want it as an array:
let colors = Array(dict.values)
and that's it.
Use colorsForColorScheme.map({$0.value})
you can create an extension on LazyMapCollection
public extension LazyMapCollection {
func toArray() -> [Element]{
return Array(self)
}
}
colorsForColorSchemes.values.toArray() or colorsForColorSchemes.keys.toArray()
Firstly, from the following statement, it seems that your variable(dictionary) name is colorsForColorScheme
var colorsForColorScheme: [ColorScheme : UIColor] = ...
while you are trying to get the values from colorsForColorSchemes dictionary when you did-
let colors: [UIColor] = colorsForColorSchemes.values
which should give you a compile time error. Anyways I am assuming that you had a typo, and you dictionary's name is colorsForColorSchemes. So, here is the solution-
As mentioned earlier, because of the type inference property in swift, your code can infer that the returned type from the .values function is returning an array of UIColor. However, Swift wants to be type-safe, so when you store the values in the colors array, you need to explicitly define that. For swift 5 and above, now you could just do following-
let colors = [UIColor](colorsForColorSchemes.values)
You can also use flatMap:
let colors = colorsForColorScheme.values.flatMap { $0 }
I've found this to be the most useful in Swift 5:
colorsForColorSchemes.allValues
See docs - https://developer.apple.com/documentation/foundation/nsdictionary/1408915-allvalues

Modifying an array of dictionaries in Swift

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