Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loop through [AnyObject]? results in does not have a member named generator

Tags:

swift

Why can't you loop through [AnyObject]? directly? What does it mean that there is no named generator? What is the proper technique for looping through an [AnyObject]? type?

This code is giving me an error telling me that it does not have a member named generator.

for screen in NSScreen.screens() {
        var result : Bool = workspace.setDesktopImageURL(imgurl, forScreen: screen, options: nil, error: &error)
}
like image 758
Mika Avatar asked Nov 10 '14 20:11

Mika


2 Answers

screens returns an optional, so before using the actual value you have to unwrap - the recommended method is optional binding:

if let screens = NSScreen.screens() {
    for screen in screens {
        var result : Bool = workspace.setDesktopImageURL(imgurl, forScreen: screen, options: nil, error: &error)
    }
}

Read more about Optionals

Note that NSScreen.screens returns [AnyObject]?, so you might want to cast the array as [NSScreen] in the optional binding:

if let screens = NSScreen.screens() as? [NSScreen] {
    for screen in screens {
        var result : Bool = workspace.setDesktopImageURL(imgurl, forScreen: screen, options: nil, error: &error)
    }
}

Addendum Answer to question in comment: why the error message says [AnyObject]? does not have a member named generator

An optional is of a different type than the value it contains (an optional is actually an enum). You can iterate an array, but you cannot iterate over an integer or an enum.

To understand the difference, let me make a real life example: you buy a new TV on ebay, the package is shipped to you, the first thing you do is to check if the package (the optional) is empty (nil). Once you verify that the TV is inside, you have to unwrap it, and put the box aside. You cannot use the TV while it's in the package. Similarly, an optional is a container: it is not the value it contains, and it doesn't have the same type. It can be empty, or it can contain a valid value.

like image 83
Antonio Avatar answered Nov 01 '22 04:11

Antonio


Here's an alternative that will save you one level of indentation:

for screen in NSScreen.screens() ?? []  {
    var result : Bool = workspace.setDesktopImageURL(imgurl, forScreen: screen, options: nil, error: &error)  
}

Using the nil-coalescing operator (??) provides an empty array in case of nil, and Swift treats screens() as non-optional.

like image 15
user2378197 Avatar answered Nov 01 '22 05:11

user2378197