Given that you have an array of optionals:
var values = [AnyObject?]
Can you use a where clause somehow before the optional binding, say, to check for a non-empty array? For example, I know that we can do this:
if !values.isEmpty {
if let value = values[0] {
// ...
}
}
And we can chain a where filter after the optional binding:
// doesn't do you any good when the array is empty
if let value = values[0] where !values.isEmpty {
// ...
}
I'd like to be able evaluate the where first, to prevent an array index out of range error:
// Not valid syntax
if where !values.isEmpty, let value = values[0] {
// ...
}
Is there some form of syntax in Swift 1.2 or 2.x that allows me to express this in a valid manner?
Very simple:
if let value = values.first {
...
}
Related
I want to refactor this Swift code with a closure syntax
var station: Station!
var allStations = [Station]()
var favoriteStationIds = [Int]()
for favoriteStationId in favoriteStationIds {
for station in allStations {
if station.stationId == favoriteStationId {
station.isFavorite = true
continue
}
}
}
You can use forEach, which have a trailing closure syntax instead of normal for ... in loops.
Moreover, you don't need to manually iterate through both arrays, you can use index(where:), that accepts a closure to find the station with the specified id as favoriteStationId.
favoriteStationIds.forEach{ id in
allStations[allStations.index(where: {$0.stationId == id})!].isFavorite = true
}
Bear in mind that above piece of code assumes all elements in favoriteStationIds are valid ids that are present in allStations (if this is not the case, use optional binding for the index instead of force unwrapping).
I want to create a dictionary out of an array and assign a new custom object to each of them. I'll do stuff with the objects later. How can I do this?
var cals = [1,2,3]
// I want to create out of this the following dictionary
// [1:ReminderList() object, 2:ReminderList() object, 3:ReminderList() object]
let calendarsHashedToReminders = cals.map { ($0, ReminderList()) } // Creating a tuple works!
let calendarsHashedToReminders = cals.map { $0: ReminderList() } // ERROR: "Consecutive statements on a line must be separated by ';'"
map() returns an Array so you'll either have to use reduce() or create the dictionary like this:
var calendars: [Int: ReminderList] = [:]
cals.forEach { calendars[$0] = ReminderList() }
You can also use reduce() to get a oneliner but I'm not a fan of using reduce() to create an Array or a Dictionary.
I'm trying to add usernames from Parse in an array to display them in a UITableView, but get an error when I'm appending the usernames to my array.
The error I get is: Cannot invoke 'append' with an argument list of type '(String?!)'
What am I doing wrong?
var usernames = [""]
func updateUsers() {
var query = PFUser.query()
query!.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
var fetchedUsers = query!.findObjects()
for fetchedUser in fetchedUsers! {
self.usernames.append(fetchedUser.username)
}
}
I solved my problem. I declare the array as an empty array and for unwrap the optional with the following code:
var usernames = [String]()
self.usernames.removeAll(keepCapacity: true)
for fetchedUser in fetchedUsers! {
if let username = fetchedUser.username as String! {
self.usernames.append(username)
}
}
PFUser.username is an optional, and you can't append an optional into a String array in Swift. This is because the optional can be nil, and a String array in Swift only accepts strings.
You need to either force unwrap the optional, or use if-let syntax to add it if it exists.
Force Unwrap
self.usernames.append(fetchedUser.username! as String)
Or if-let
if let name = fetchedUser.username as? String {
self.usernames.append(name)
}
Plus as NRKirby mentions in the comments on your question, you might want to look at initialising the usernames array differently. At the moment the first element is an empty string.
I want to check if there is a value in a array and if so assign to a String using a if-left statement:
if let scoreValue = scoreValueArray[element!]{
// do something with scoreValue
}
Error: Bound value in a conditional binding must be of optional type
So tried changing the ! to ? but error persists.
Any input appreciated.
scoreValueArray is an array of strings, where a String value is appended to array if a condition is met, then array is saved to NSUserdefaults.
So element is a int which corresponds to a index in the array, bt only if the index is occupied with a String, so
scoreValueArray[element!]
could return an 'Index out of bounds', hence want to use the if-let.
Although the accepted answer clearly puts why optional binding is not available in the current implementation, it doesn't provide with a solution.
As it is shown in this answer, protocols provide an elegant way of safely checking the bounds of an array. Here's the Swift 2.0 version:
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
Which you can use like this:
let fruits = ["Apple", "Banana", "Cherry"]
if let fruit = fruits[safe: 4] {
// Do something with the fruit
}
It's not clear what type your scoreValueArray is, but for the sake of this answer, I'm going to assume it's an array of Int.
var scoreValueArray: Array<Int>
Now, if we look the definition of the Array struct, we'll find this:
struct Array<T> : MutableCollectionType, Sliceable {
// other stuff...
subscript (index: Int) -> T
// more stuff
}
So, calling the subscript method on our array (which is what we do when we say scoreValueArray) returns a non-optional. And non-optionals cannot be used in the conditional binding if let/if var statements.
We can duplicate this error message in a more simple example:
let foo: Int = 3
if let bar = foo {
// same error
}
This produces the same error. If we instead do something more like the following, we can avoid the error:
let foo: Int? = 3
if let bar = foo {
// perfectly valid
}
This is different from a dictionary, whose subscript method does return an optional (T?). A dictionary will return a value if the key passed in the subscript is found or nil if there is no value for the passed key.
We must avoid array-index-out-of-bounds exceptions in the same way we always do... by checking the array's length:
if element < scoreValueArray.count {
scoreValue = scoreValueArray[element]
}
I am getting a compile error saying
Bound value in a conditional binding must be an Optional type
Below is a screenshot of the code
You can convert the value of array[index] to an Optional doing something like this:
if let value = Int?(array[index]){
result += value
}
That's if your array contains Ints. You could also use AnyObject?, but you'll get a warning from xcode.
The array should be declared as Optional type, take Int?[] as an example,
let array:Int?[] = [nil, 2, 3]
let index = 0
let count = array.count
for index in 0..count {
if let value = array[index] {
println(value)
} else {
println("no value")
}
}
if the type of the value of array[index] is of optional, you could simple do like this:
if let value = array[index]{
result += value
}
In this case the compiler is complaining because array isn't a collection of Optional (nil-able) types. If it truly doesn't need to be, you don't actually need that if, since everything inside the array is guaranteed to be the same type, and that if statement won't protect you from a out-of-bounds error anyway. So just go with:
while ++index < length {
result += array[index]
}
or perhaps better:
for value in array {
result += value
}
or even better:
result = array.reduce(0) { $0 + $1 }