I have a method that iterates over an array and call other method with every element as argument. If I declare this method as:
func didFinishedListFiles(files: [FileModel]) {
for var fileData in files {
self.downloadSingleFile(NSUUID(UUIDString: fileData.uuid!)!);
}
}
Xcode shows a warning:
Variable 'fileData' was never mutated; consider changing to 'let' constant
But if I change var to let:
func didFinishedListFiles(files: [FileModel]) {
for let fileData in files {
self.downloadSingleFile(NSUUID(UUIDString: fileData.uuid!)!);
}
}
Xcode shows an error:
'let' pattern cannot appear nested in an already immutable context
How is a correct way to implement it without any warnings/errors?
The for-in pattern implicitly uses a constant binding (in the scope it creates. That is, your fileData binding is automatically a local let, and therefore constant for each pass through the loop.
So the following:
for fileData in files { /*...*/ }
...is equivalent to :
var index = 0
while index < files.count {
let fileData = files[index]
//...
index += 1
}
You'd want to add var to the for-in binding only when you want to mutate that binding -- that is, if it's an object reference that you want to be able to point at something else during a single pass through the loop, or a value type that you want to be able to change. But it doesn't look like you're doing either of those things, so using var for this binding would be superfluous here.
(Swift 3 got rid of a lot of the places where you could make implicitly immutable bindings mutable, but left for var as an exception — it's still possible if you want to change something during a loop.)
Related
I'm having trouble adding elements to an object that keeps a collection of generic-typed values. I tried a Minimal Working Example that causes the error:
class OneElementQueue {
type eltType;
var elements : [0..0] eltType;
//initializer
proc init(type eltType) {
this.eltType = eltType;
}
proc add(element : eltType) {
this.elements[0] = element;
}
proc remove() : eltType {
return this.elements[0];
}
} //end of OneElementQueue
class Monkey {
var name: string;
var age: int;
proc init(name : string, age : int) {
this.name = name;
this.age = age;
}
} //end of class Monkey
var q = new owned OneElementQueue(Monkey);
var m = new owned Monkey("Kyle", 6);
q.add(m);
When I try to compile all of this, I get an error:
$ chpl BadQueue.chpl
BadQueue.chpl:12: In function 'add':
BadQueue.chpl:13: error: Scoped variable would outlive the value it is set to
BadQueue.chpl:12: note: consider scope of element
$
What is the correct way to go about adding something to a generic data structure like this? How am I going about this the wrong way?
There are two possible approaches you can take here, depending on what behavior you want:
"I want to have my collection take ownership of the Monkey objects"
In this case, you'll want to instantiate your OneElementQueue collection to store owned Monkey objects rather than simply [borrowed] Monkey objects, which is the default for class types. You can do this with the one line change (Try it Online):
var q = new owned OneElementQueue(owned Monkey);
In this approach, passing an owned Monkey to your add() method will pass the ownership to the argument and eventually to the collection, making the original object reference invalid (nil).
"I want to have my collection borrow the existing Monkey objects without taking ownership of them"
In this case, you'll need to tell the add() method that the argument passed into it will outlive the argument itself (and then be sure not to lie about it). In Chapel version 1.19, this can be done via lifetime annotations:
proc add(element : eltType) lifetime element > this {
where the annotation lifetime element > this asserts that the actual argument passed through element will outlive the this collection itself, so the compiler should not fear that the borrow will cease to exist once the formal argument has.
Lifetime annotations were not available in Chapel 1.18, so if you're using that version you need to use a slightly bigger hammer and apply pragma "unsafe" to the method. Note that pragmas are not an officially supported feature and may change in the future, so for this case, served as a stopgap until lifetime annotations had been implemented (Try it Online):
pragma "unsafe"
proc add(element : eltType) {
How do I convert an Observable of type Int to a Variable of type Int?
Here is what I have tried so far:
let obs: Observable<Int> = Observable.of(4)
let variable: Variable<Int> = obs
.flatMap { num in
return Variable<Int>(num)
}
Using flatMap feels like the most logical way of doing the conversion, however, I get a compiler error which essentially says that it does not like the flatMap returning anything that is not an observable. Any ideas?
EDIT:
Just to give some context as to why I need to convert the Observable into a Variable:
I need my viewModel to drive a UIPickerView inside a ViewController. Currently, I have two exposed properties in my ViewModel, items: Observable<[String]> (which is the datasource for the UIPickerView) and selectedIndex: Variable. The selectedIndex will drive the initial value of the UIPickerView but also keep track of any changes the user makes.
The reason I needed to convert from the Observable to Variable was that I needed to figure out which index of the UIPickerView should be selected initially:
items.map { days -> Int in
if let index = days.index(where: { str in
return str == selectedDay
}) {
return index
}
return 0
}
.flatMap { num in
return Variable<Int>(num)
}
I'm now wondering if I'm over complicating things, and if instead of the Variable in I should just have an Observable.
A few points here:
First, You should not use Variable as it's deprecated (gonna be entirely deprecated in Swift 5 probably). Look at BehaviorSubject and BehaviorRelay instead.
About your question, I'm not sure what is the use case for having a Variable equal to an Observable, so there are two different thoughts I have:
You can bind an Observable to a Variable/Subject/Relay (e.g. observable.bind(to: variable))
You can actually go the other way around an get an Observable from the Variable, which might make more sense. e.g. variable.asObservable()
I'm new to Swift. I'm having dictionary and i'm passing it to some method which should be able to modify it. What's the best solution for it, return new Dictionary (seems to be inefficient because of copying needed):
func method(let dict : [String:String]) -> [String:String] {
var newDictionary = [String:String]()
... // copy to newDictionary/remove existing items
}
or pass it as inout argument (is it working?):
func method(inout dict : [String:String]) {
... // modify existing dictionary
}
An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value.
As said here, it will modify the instance that is passed as inout parameter. So in your case it's definitively what you want to do, in my opinion.
https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html ctrl+f "inout"
I had working code to remove all map annotations with a button, but after my update to xcode 7 I am running into the error:
Type 'MKAnnotation' does not conform to protocol 'SequenceType'
if let annotations = (self.mapView.annotations as? MKAnnotation){
for _annotation in annotations {
if let annotation = _annotation as? MKAnnotation {
self.mapView.removeAnnotation(annotation)
}
}
}
In Swift 2 annotations is declared as non optional array [MKAnnotation] so you can easily write
let allAnnotations = self.mapView.annotations
self.mapView.removeAnnotations(allAnnotations)
without any type casting.
self.mapView.removeAnnotations(self.mapView.annotations)
If you don't want remove user location.
self.mapView.annotations.forEach {
if !($0 is MKUserLocation) {
self.mapView.removeAnnotation($0)
}
}
Note: Objective-C now have generics, it is no longer necessary cast the elements of 'annotations' array.
SWIFT 5
If you don't want to remove user location mark:
let annotations = mapView.annotations.filter({ !($0 is MKUserLocation) })
mapView.removeAnnotations(annotations)
The issue is that there are two methods. One is removeAnnotation which takes an MKAnnotation object, and the other is removeAnnotations which takes an array of MKAnnotations, note the "s" at the end of one and not the other. Attempting to cast from [MKAnnotation], an array to MKAnnotation a single object or visa versa will crash the program. The line of code self.mapView.annotations creates an array. Thus, if you are using the method removeAnnotation, you need to index the array for a single object within the array, as seen below:
let previousAnnotations = self.mapView.annotations
if !previousAnnotations.isEmpty{
self.mapView.removeAnnotation(previousAnnotations[0])
}
Thus, you can remove various annotations while keeping the users location. You should always test your array before attempting to remove objects from it, else there is the possibly getting an out of bounds or nil error.
Note: using the method removeAnnotations (with an s)removes all annotations.
If you are getting a nil, that implies that you have an empty array. You can verify that by adding an else statement after the if, like so;
else{print("empty array")}
I noticed that when a variable is captured by a closure in Swift, the closure can actually modify the value. This seems crazy to me and an excellent way of getting horrendous bugs, specially when the same var is captured by several closures.
var capture = "Hello captured"
func g(){
// this shouldn't be possible!
capture = capture + "!"
}
g()
capture
On the other hand, there's the inout parameters, which allow a function or closure to modify its parameters.
What's the need for inout, even captured variables can already be modified with impunity??!!
Just trying to understand the design decisions behind this...
Variables from an outer scope that are captured aren't parameters to the routine, hence their mutablility is inherited from context. By default actual parameters to a routine are constant (let) and hence can't be modified locally (and their value isn't returned)
Also note that your example isn't really capturing capture since it's a global variable.
var global = "Global"
func function(nonmutable:Int, var mutable:Int, inout returnable:Int) -> Void {
// global can be modified here because it's a global (not captured!)
global = "Global 2"
// nomutable can't be modified
// nonmutable = 3
// mutable can be modified, but it's caller won't see the change
mutable = 4
// returnable can be modified, and it's caller sees the change
returnable = 5
}
var nonmutable = 1
var mutable = 2
var output = 3
function(nonmutable, mutable, &output)
println("nonmutable = \(nonmutable)")
println("mutable = \(mutable)")
println("output = \(output)")
Also, as you can see, the inout parameter is passed differently so that it's obvious that on return, the value may be different.
David's answer is totally correct, but I thought I'd give an example how capture actually works as well:
func captureMe() -> (String) -> () {
// v~~~ This will get 'captured' by the closure that is returned:
var capturedString = "captured"
return {
// The closure that is returned will print the old value,
// assign a new value to 'capturedString', and then
// print the new value as well:
println("Old value: \(capturedString)")
capturedString = $0
println("New value: \(capturedString)")
}
}
let test1 = captureMe() // Output: Old value: captured
println(test1("altered")) // New value: altered
// But each new time that 'captureMe()' is called, a new instance
// of 'capturedString' is created with the same initial value:
let test2 = captureMe() // Output: Old value: captured
println(test2("altered again...")) // New value: altered again...
// Old value will always start out as "captured" for every
// new function that captureMe() returns.
The upshot of that is that you don't have to worry about the closure altering the captured value - yes, it can alter it, but only for that particular instance of the returned closure. All other instances of the returned closure will get their own, independent copy of the captured value that they, and only they, can alter.
Here are a couple of use cases for closures capturing variables outside their local context, that may help see why this feature is useful:
Suppose you want to filter duplicates out of an array. There’s a filter function that takes a filtering predicate and returns a new array of only entries matching that predicate. But how to pass the state of which entries have already been seen and are thus duplicates? You’d need the predicate to keep state between calls – and you can do this by having the predicate capture a variable that holds that state:
func removeDupes<T: Hashable>(source: [T]) -> [T] {
// “seen” is a dictionary used to track duplicates
var seen: [T:Bool] = [:]
return source.filter { // brace marks the start of a closure expression
// the closure captures the dictionary and updates it
seen.updateValue(true, forKey: $0) == nil
}
}
// prints [1,2,3,4]
removeDupes([1,2,3,1,1,2,4])
It’s true that you could replicate this functionality with a filter function that also took an inout argument – but it would be hard to write something so generic yet flexible as the possibilities with closures. (you could do this kind of filter with reduce instead of filter, since reduce passes state from call to call – but the filter version is probably clearer)
There is a GeneratorOf struct in the standard library that makes it very easy to whip up sequence generators of various kinds. You initialize it with a closure, and that closure can capture variables to use for the state of the generator.
Suppose you want a generator that serves up a random ascending sequence of m numbers from a range 0 to n. Here’s how to do that with GeneratorOf:
import Darwin
func randomGeneratorOf(#n: Int, #from: Int) -> GeneratorOf<Int> {
// state variable to capture in the closure
var select = UInt32(n)
var remaining = UInt32(from)
var i = 0
return GeneratorOf {
while i < from {
if arc4random_uniform(remaining) < select {
--select
--remaining
return i++
}
else {
--remaining
++i
}
}
// returning nil marks the end of the sequence
return nil
}
}
var g = randomGeneratorOf(n: 5, from: 20)
// prints 5 random numbers in 0..<20
println(",".join(map(g,toString)))
Again, it’s possible to do this kind of thing without closures – in languages without them, you’d probably have a generator protocol/interface and create an object that held state and had a method that served up values. But closure expressions allow a flexible way to do this with minimal boiler plate.
A closure being able to modify the captured variable in the outer scope is pretty common across languages. This is the default behavior in C#, JavaScript, Perl, PHP, Ruby, Common Lisp, Scheme, Smalltalk, and many others. This is also the behavior in Objective-C if the outer variable is __block, in Python 3 if the outer variable is nonlocal, in C++ if the outer variable is captured with &