Cannot assign to "" in "self" - Working with Tuples in Swift - arrays

I have to classes: FirstViewController and PlanGenerator.
PlanGenerator has a method called getPlanForIndex (day:Int) -> ([PlanElement], [PlanElement])?. It is returning two different Arrays, both containing Object of Plan Element.
getPlanForIndex (day:Int) -> ([PlanElement], [PlanElement])? {
// Do some work and fill arrays
return (firstArray, secondArray)
}
In the FirstViewController I've created two Properties:
let plan:[PlanElement] = [PlanElement]()
let planGen:PlanGenerator = PlanGenerator()
FirstViewControllerhas a method called:
func prepareView () {
plan = planGen.getPlanForIndex(dayIndex)
}
But when I want to call this, I get the error message:
Cannot assign to 'plan' in 'self'

First, your plan member is a constant (declared with let), and you're assigning to it outside of init. If you want to assign to it after initialization, it needs to be declared with var.
Also, your getPlanForIndex returns a tuple, and you're assigning it to a member of singular (not tuple) type. If you want to assign one part of a tuple only, do it like this:
(plan, _) = planGen.getPlanForIndex(dayIndex)
That assigns a tuple to a tuple, satisfying the compiler, but discards the second element.
If you instead want plan to be a tuple, you'll have to declare and initialize it as such. Looks from the comments like you figured out a way to do that, but here's a way with minimal typing (in either sense of the word):
var plan: ([PlanElement], [PlanElement]) = ([], [])
(Once you've declared the type of array, [] is understood to be an empty array of that type. Just var plan = ([], []) leaves the type ambiguous.)

Related

Typescript array.splice() function weird behavior [duplicate]

In a Mozilla developer translated Korean lang says 'slice method' returns a new array copied shallowly.
so I tested my code.
var animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
var t = animals.slice(2,4);
console.log(t);
t[0] = 'aaa';
console.log(t);
console.log(animals);
but, If slice method returns shallow array, the animals array should be changed with ['ant', 'bison', 'aaa', 'duck', 'elephant'].
Why is it shallow copy?
slice does not alter the original array.
It returns a shallow copy of elements from the original array.
Elements of the original array are copied into the returned array as follows:
For object references (and not the actual object), slice copies object references into the new array. Both the original and new array refer to the same object. If a referenced object changes, the changes are visible to both the new and original arrays.
For strings, numbers and booleans (not String, Number and Boolean objects), slice copies the values into the new array. Changes to the string, number or boolean in one array do not affect the other array.
If a new element is added to either array, the other array is not affected.(source)
In your case the the array consists of strings which on slice would return new strings copied to the array thus is a shallow copy.
In order to avoid this use the object form of array.
strings are primitive types in JavaScript, so you will get a new array with new strings inside.
Your test array should be an array of objects:
var animals = [{name: 'ant'}, {name: 'bison'}, {name: 'camel'}, {name: 'duck'}, {name: 'elephant'}];
var t = animals.slice(2,4);
console.log(t);
t[0].name = 'aaa';
console.log(t);
console.log(animals);
The slice method doesn't change the original array or string. It only cuts a portion of the original string or array and returns it as a copy.
For more understanding of it, kindly check this video below:
https://youtu.be/mUH8hPQfMbg [Slice method made easy for absolute beginners]
May be you are looking for this. Try this!
let animals = ['ant', 'bison', 'camel', [1, 2]];
let t = animals.slice();
t[0] = 'aaa'; // string (primitive datatype)
t[t.length-1][0] = 0; // array (object)
console.log(t);
console.log(animals);
In case of a shallow copy-
Objects will reflect change in the original place from where they were shallowly copied because they are stored as references (to their address in the Heap).
Primitive data types will NOT reflect change in the original place because they are directly stored in the callstack (in Execution Contexts).

Better way to deal with optional variable and array operation in Swift

I have a following code, which copies an array of Rider objects, and appends a new Rider object if it exists.
let riders:[Rider] = getRiders()
let newRider:Rider? = mayGetNewRider()
var ridersPlus = riders
if let rider = newRider {
ridersPlus.append(rider)
}
I am looking for a better (simpler and easier to read) way to write this logic, which also allows me to define ridersPlus as "let" variable.
I am looking for something like below (which is invalid, because I made up the ??? syntax, which produces an empty array of newRider is nil).
let riders:[Rider] = getRiders()
let newRider:Rider? = mayGetNewRider()
let ridersPlus = riders + [newRider???]
How about
let ridersPlus = riders + [newRider].compactMap {$0}
(Note that before Swift 4, compactMap would be called flatMap. You didn't say what Swift version you are using.)
You do it with map and the nil coalescing operator ??:
let ridersPlus = riders + (newRider.map {[$0]} ?? [])
map when called on an Optional value evaluates the given closure when the Optional instance is not nil, passing the unwrapped value as a parameter. If the Optional is nil, the result of the map is nil. Combining that with the nil coalescing operator, the resulting Optional array can be unwrapped or replaced with [] and then added to the riders array.

Swift - if string is nil. don't add it to the array

I have an Array of Image links -
let alamofireSource = [AlamofireSource(urlString: Img1!)!, AlamofireSource(urlString: Img2!)!,
AlamofireSource(urlString: Img3!)!, AlamofireSource(urlString: Img4!)!]
slideshow.setImageInputs(alamofireSource)
some posts have only one image or two or three, and so on. so, sometimes image 2 (for example) is nil, In that case, I don't want it to be added to the array, is that possible?
You can try ( Swift 4 )
let arr = [img1,img2].compactMap{$0}.map{AlamofireSource(urlString:$0)!}
or
let arr = alamofireSource.compactMap{$0}
for Swift 3
let arr = alamofireSource.flatMap{$0}
so, sometimes image 2 (for example) is nil, In that case, I don't want
it to be added to the array, is that possible?
Yes it is. Although I would go with Sh_Khan's suggestion to use the compactMap method to achieve it, but it would be useless for your current case:
Based on your code snippet, I'd assume that alamofireSource of type [AlamofireSource], but not [AlamofireSource?] and that's because you are forcibly unwrap its elements (by adding ! to each of its elements). So far alamofireSource doesn't contain nils (actually it could be more danger than just a declaration, your app might crash!)
So first of all, I would recommend to remove the ! from alamofireSource:
let alamofireSource = [AlamofireSource(urlString: Img1!),
AlamofireSource(urlString: Img2!),
AlamofireSource(urlString: Img3!),
AlamofireSource(urlString: Img4!)]
which means let it be as [AlamofireSource?], therefore you would gain the benefit of using compactMap(_:):
Returns an array containing the non-nil results of calling the given
transformation with each element of this sequence.
As:
let alamofireSourceWihoutNils = alamofireSource.compactMap { $0 }
Assuming you put your Optional url strings into an array, say urlStrings (of type [String?]), you can construct alamofireSource according to (Swift 4):
let alamofireSource = urlStrings.compactMap { $0.map(AlamofireSource.init) }
Which make use of the map(_:) operator of Optional and compactMap(_:) to unwrap the two-level optionality.
Details
Your example contains two levels of optionality:
The optional ImgX arguments of type String? - henceforth referred to and named as img1, ..., img4, as CapitalFirstLetter names are reserved for e.g. types, not type instances.
The failable initilizer init?(urlString: String, placeholder: UIImage? = nil) of AlamofireSource.
First of all, lets gather the optional image links (imgX) into an array
let urlStrings = [url1, url2, url3, url4] // [String?]
Swift 4
You can combine the map(_:) operator of Optional with compactMap(_:) to safely unwrap and make use of the .some entires of urlStrings, thereafter collect the successful invocations of the failable initializer of AlamofireSource:
let alamofireSource = urlStrings.compactMap { $0.map(AlamofireSource.init) }
// or, use a named closure argument
let alamofireSource = urlStrings.compactMap { str in str.map(AlamofireSource.init) }
Swift 3
If using Swift 3, replace the compactMap(_:) invocation above with flatMap(_:):
let alamofireSource = urlStrings.flatMap { $0.map(AlamofireSource.init) }
// or, use a named closure argument
let alamofireSource = urlStrings.flatMap { str in str.map(AlamofireSource.init) }

can you declare an empty array, without knowing the type in swift

for example:
let myArray:[] = []
or
let myArray = []
The first one is not possible (it will complain about expected element type) If you don't know the element type you can use AnyObject but if you know the type of it you have to put it there (Int,Double,String, AnyObject, etc...).
var myArrayOfDoubles:[Double] = []
The second one (when omitting the type) is OK ONLY if you initialize it with some values but If you try it with an empty array you won't be able to append anything (at least using Playground) saying that NSArray does not have a member named append.
var myArrayOfInts = [1,2,3,4,5] // [Int]
var myArrayOfAnyObject:[AnyObject] = [] // [AnyObject]
And finally last but not least you have to define it as var because if you define it using let it will stay empty forever :)
Yes, you can, it can be Any or Anyobject...
example:
var noTypeArray = [Any]()
If you want to fill the array eventually it may be var, no let, there's no point otherwise.
No. If you don't know what will go in use this:
var myArray = [Any]()
Apple has introduced a Type-GeStaPo and you must type anything that's not up the tree at count three.
To add to this use
myArray.append("this")
myArray.append(1)
myArray.append(myObject)

Using arrays in Swift

Just started using Swift and I'm getting pissed at a few elements. First is that most standard stuff are structs rather than objects, which means they're passed in as values rather than pointers as I'm used to. The other thing is that using the optional element system is really annoying.
If I am trying to declare an array without putting anything in it, I declare it like this:
var theArray : [Int]
In order to put anything in it, I would declare it like this:
var theArray : [Int]?
Then add objects as follows:
theArray[someIndex] = someInt
//or
theArray.append(someInt)
However, I get an error. In Java, I could have just initialized an array with a length, which would have given me an a fixed-size array with all 0's.
The problem, summarized in a sentence, is adding elements to Swift arrays that have been initialized without values. How do you do this?
In order to initialize an empty array use:
var theArray : [Int] = []
then add elements by using append method. What you currently did is that you just declared it in the first case non optional and in the second case as an optional variable typed as int array without initializing it.
If you want the array to contain Int types, of course there are many ways to declare that, based on implicit or explicit type inference. These are all valid declarations of an array containing Int types
var array1 = [Int]()
var array2: [Int] = []
var array3 = Array<Int>()
var array4: Array<Int> = []
If you want an array of a certain size, with the values initialized to a certain value you can use, in this example you'll get an Array<Int> with 5 elements, all initialised to 0
var array = Array(count: 5, repeatedValue: Int(0))
Here you go:
var theArray = Array(count:[the length you want], repeatedValue:Int(0))
This will replicate the Java behaviour.

Resources