Why <Element> is not needed when creating default value array in Swift? - ios

The code below is excerpted from The Swift Programming Language (Swift 4.2) of Apple documentation.
Now consider this: there are 3 ways to create an empty array in Swift.
First:
var list1 = Array<String>()
Second:
var list2: [String] = []
Third:
var list3 = [String]()
In order to create a default value array, we make use of repeating: and count:
var list4 = Array(repeating: "Apples", count: 3)
The above array is created using the first form of array creation, however, why it is not needed to declare the <Element> next to Array initializer.
Trying to create a normal empty array without specifying which type inside the <Element> would trigger a runtime error.
var list5 = Array("Apples") //A,p,p,l,e,s
var list6 = Array("Apples", "Oranges") //return an error
Why this happens?

Because it knows the type of the first item. Since Arrays only contain objects of a single type, of it can get that information from the first item, then it is enough.
Following your comment:
I think you are getting confused with the first item. "Oranges" is an array of [Character] so when you use Array("Oranges") you are creating an array of characters. For your third item, rather than passing in two values, which an Array doesn't know how to deal with, pass in an array like this: let list6 = Array(["Apples", "Oranges"])

Related

Swift 3 build array (Don't know how to describe)

First of all, sorry for the unclear title, but I don't know how to describe my problem or how to search for it. (Still a beginner)
So I have an array where I need to put values in.
let heliosDataArray:String = "[{\"timestamp\":\"\(timestamp)\",\"uv\":\"\(uvIndex!)\",\"light\":\"\(lightvalue!)\"}]"
So in this "template" I need to add 3 values: timestamp, uvIndex and lightValue. So far so good. Now I have a lot of values and for an API call I need to to chain this array multiple times in to 1 array, kind of like a master array. What is the most practical way of doing this? The amount of data is variable, and comes from CoreData. Probably going to put the values first in arrays. What should I be searching for? I was thinking a loop but like more advanced?
Thanks in advance
You can approach with object-oriented logic:
struct Data {
var timestamp: Double?
var lightValue: Double?
var uvIndex: Int?
}
let data1 = Data(timestamp: 13.4, lightValue: 3.4, uvIndex: 4)
let data2 = Data(timestamp: 12.4, lightValue: 2.4, uvIndex: 3)
let data3 = Data(timestamp: 11.4, lightValue: 1.4, uvIndex: 2)
var dataArray = Array<Data>() // or-> var data = [Data]()
dataArray.append(data1)
dataArray.append(data2)
dataArray.append(data3)
You can do this in many ways. One of them is shown below
let say you have three values from coredata timestamp, uvIndex and lightvalue
Seems what you are asking is a array of dictionaries, first you need is a dictionary of the values you got from CoreData, let call them dayItem
var dayItem = ["timestamp": timestamp,
"uv": uvIndex,
"light": lightValue]
Now create an array of values
var dayArray: [[String: Any]] = []
dayArray.append(dayItem)
Every time you want to append new items just use the append method of array

How can NSMutableArray add object using let in swift

I created a NSMutableArray in swift using let and
when I add addObject in the mutableArray then it will add it even though I
used the let to assign a constant. Can anyone explain how let works in swift? If it doesn't allow you to add value in later then how is the following
code working?
let arr : NSMutableArray = [1,2,3,4,5]
arr.addObject(6)
println(arr)
Classes are reference types, and NSMutableArray is a class.
Foundation's NSMutableArray is different from Swift's Array: the latter is a value type.
If you create a constant NSMutableArray:
let ns: NSMutableArray = ["a", "b"]
then this works:
ns.addObject("c")
but this doesn't:
ns = ["d", "e"] // nope!
because you can change the content of the reference but you can't change what is assigned to the constant.
On the other hand, with Swift's Array:
let sw: [String] = ["a", "b"]
the constant can't be changed because it's a value, not a reference.
sw.append("c") // nope!
Doc: Structures and Enumerations Are Value Types and Classes Are Reference Types
disclaimer: this answer only applies to NS type data structures, please see #Eric D's answer for the full picture
let when used with a class just means the variable cant be changed, eg, to another array. If you dont want the array to be editable, use a normal NSArray and not a mutable one
let arr : NSMutableArray = [1,2,3,4,5]
arr = [1,2,3,4,5] //error trying to assign to a let variable that has already been assigned
arr.addObject(6) //fine because we are not changing what is assigned to arr, but we are allowed to change the object that is assigned to arr itself
I think your understanding of what a constant variable is, is a bit too strict.

Creating and populating an empty Array

I'm actually learning swift in order to develop iOS apps. I'd like, as an exercise, to create and populate an empty array, that would be filled by using a textfield and a button on the storyboard.
var arr = []
// When button is pressed :
arr.append(textfield.text)
XCode tells me that the append method is not a method of NSArray. So I have used the addObject one, but it is still not correct as the arr variable contains nil.
So here are my three questions :
Is it possible to create an empty array, and if so, how to populate it ?
Sometimes, in my ViewController, when I create a non-empty array, the append method is apparently not valid, and I don't understand why..
Finally, why even though I use the syntax :
var arr = [1] // For example
The arr object is NSArray object and not a NSMutableArray object, making it impossible to add/remove any object that is contained in it?
I hope my questions are clear, if not I'll upload more code of what I'm trying to build,
thank you for your answers !
Try to define your array as a String array, like this:
var arr: [String] = []
And then append to your list, either by:
arr.append("the string")
or
arr += ["the string"]
Empty array can be created using the following syntax.
var emptyArray = [String]()
emptyArray.append("Hi")
see this
You can use following also to add elements to your array.
//append - to add only one element
emptyArray.append("Hi")
//To add multiple elements
emptyArray += ["Hello", "How r u"]
emptyArray.extend(["am fine", "How r u"])
//Insert at specific index
emptyArray.insert("Who r u", atIndex: 1)
//To insert another array objects
var array1 = ["who", "what", "why"]
emptyArray.splice(array1, atIndex: 1)

How does one create a mutable copy of an immutable array in swift?

Now that Swift's Array's are truly immutable thanks to full value semantics, how can I create an mutable copy of an immutable array? Similar to Obj-C mutableCopy(). I can of course downcast the array to an NSArray and use mutableCopy() but don't want to use NSArray because it does not strictly typed.
I have a toolbar which has items from the storyboard. I want to remove an item from the toolbar and use toolbar.setItems. I wanted to do it without casting as a NSArray, because none of these functions take NSArrays, they take [AnyObject].
Obviously now when I call removeAtIndex() it does not work, which is correct. I just need a mutableCopy
Simply assigning to var does not work for me and give 'Immutable value of type [AnyObject]'
var toolbarItems = self.toolbar.items
toolbarItems.removeAtIndex(2) //Immutable value of type [AnyObject]
I am using Beta 3
The problem is that self.toolbar.items is an implicitly unwrapped optional (of type [AnyObject]!) and they are always immutable. When you assign to the variable toolbarItems without explicitly stating its type, it too becomes an implicitly unwrapped optional, and thus is immutable as well.
To fix this do either:
var toolbarItems:[AnyObject] = self.toolbar.items
toolbarItems.removeAtIndex(2)
Or:
var toolbarItems = self.toolbar.items as [AnyObject]
toolbarItems.removeAtIndex(2)
Update
As of Xcode 6 Beta 5, you can update collections that are stored in optional variables, so the original code now works:
var toolbarItems = self.toolbar.items
toolbarItems.removeAtIndex(2)
Arrays are value types (struct), so they are passed around by value and not by reference.
That said, if you create a variable of array type and assign it the immutable array, a copy of the immutable array is actually created and assigned to it - and of course that copy has no relationship with the original immutable array (besides having the same values at the time it is created).
let immutable = [1, 2, 3]
//immutable[0] = 1 // Fails, ok
var mutable = immutable
mutable[0] = 5
In your case, you are accessing an immutable array which is an NSArray of AnyObjects (see documentation). You can use it as an Array in swift, make a copy of it and modify as follows:
let immutable : NSArray = [ 1, 2, 3 ]
//immutable[0] = 1 // Fails, ok
var mutable : [AnyObject] = immutable
mutable.removeAtIndex(1) // mutable now is [1, 3]
mutable[0] = 7 // mutable now is [7, 3]
After you're done with your changes, you can assign to the items property
It is as simple as declaring a var with your array.
var items = toolbar.items
Now you can change items and then reassign to the toolbar.
toolbar.items = items
Note that you can cannot (as of Beta 3) alter the elements of an "immutable" array declared with let as well. Just the length of the array is was fixed, which is why you cannot remove items.
However, according to Apple's documentation of UIToolbar, the items array is already mutable.
SWIFT
var items: [AnyObject]!
Tested + works:
var mutable : [UIBarButtonItem] = []
for button in toolbar.items {
mutable += button as UIBarButtonItem
}
mutable.removeAtIndex(2)
toolbar.setItems(mutable, animated: true)
TO REMOVE AN OBJECT FROM PARTICULAR INDEX OF AN ARRAY.
let fullArray : NSArray = Userdefaults().value(forKey: "YOUR_ARRAY_STRING") as! NSArray
var mutableArray : [AnyObject] = fullArray as [AnyObject]
mutableArray.remove(at: INDEX_TO_REMOVE) //Eg: mutableArray.remove(at: 0)
mutableArray.append(ARRAY_TO_APPEND)
In Beta3 constant arrays are completely immutable while variable arrays are entirely mutable. So just change let array:to var array: and then verify your code

Swift: Creating an array of UIImage

Using Swift, I'm trying to create an array of UIImage objects for a simple animation. Contextual help for animationImages reads, "The array must contain UI Image objects."
I've tried to create said array as follows, but can't seem to get the syntax correct:
var logoImages: UIImage[]
logoImages[0] = UIImage(name: "logo.png")
This throws:
! Variable logoImages used before being initialized
Then I tried
var logoImages = []
logoImages[0] = UIImage(named: "logo.png")
Which throws:
! Cannot assign to the result of this expression
I've checked the docs here, but the context isn't the same:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html
You have two problems (and without a regex!)
1. You aren't creating an array. You need to do:
var logoImages: [UIImage] = []
or
var logoImages: Array<UIImage> = []
or
var logoImages = [UIImage]()
or
var logoImages = Array<UIImage>()
2. If you want to add new objects to an array, you should use Array.append() or some of the equivalent syntactic sugar:
logoImages.append(UIImage(named: "logo.png")!)
or
logoImages += [UIImage(named: "logo.png")!]
or
logoImages += [UIImage(named: "logo.png")!, UIImage(named: "logo2.png")!]
You need to append to the array because (excerpt from docs):
You can’t use subscript syntax to append a new item to the end of an
array. If you try to use subscript syntax to retrieve or set a value
for an index that is outside of an array’s existing bounds, you will
trigger a runtime error. However, you can check that an index is valid
before using it, by comparing it to the array’s count property. Except
when count is 0 (meaning the array is empty), the largest valid index
in an array will always be count - 1, because arrays are indexed from
zero.
Of course you could always simplify it when possible:
var logoImage: [UIImage] = [
UIImage(named: "logo1.png")!,
UIImage(named: "logo2.png")!
]
edit: Note that UIImage now has a "failable" initializer, meaning that it returns an optional. I've updated all the bits of code to reflect this change as well as changes to the array syntax.
You are declaring the type for logoImages but not creating an instance of that type.
Use var logoImages = UIImage[]() which will create a new array for you.
...and then after creating a new empty Array instance, as described in the answer by #Jiaaro you can't use subscripting to add to an empty array
var image : UIImage = UIImage(named:"logo.png")
var logoImages = [image]

Resources