darkginger
darkginger

Reputation: 690

Using a variable outside of a do loop in Swift 3

Using this answer, I would like to assign a string to a variable in my ViewDidLoad, as I will use this array to populate a table.

let downloads : String?

// Get the document directory url
let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

do {
    // Get the directory contents urls (including subfolders urls)
    let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: [])
    print(directoryContents)

    // if you want to filter the directory contents you can do like this:
    let mp3Files = directoryContents.filter{ $0.pathExtension == "mp3" }
    //print("mp3 urls:",mp3Files)
    let mp3FileNames = mp3Files.map{ $0.deletingPathExtension().lastPathComponent }
    //print("mp3 list:", mp3FileNames)

    let downloads = mp3FileNames

} catch {
    print(error.localizedDescription)
}

First, if I print mp3FileNames without the variable, it prints. So the mp3 download extracting code seems good.

Second, when I add the variable for downloads, things break down. XCode flags that I am not using the variable elsewhere even though it reappears in my do loop: Immutable value 'cars' was never used; consider replacing with '_' or removing it

I am new to Swift. What is the proper way to set this variable with the string that will come from mp3FileNames?

Upvotes: 0

Views: 1092

Answers (3)

Milan Nosáľ
Milan Nosáľ

Reputation: 19757

This is the solution you are looking for:

// not a string, but an array of strings
let downloads : [String]?

let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

do {
    let directoryContents = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: [])
    print(directoryContents)

    let mp3Files = directoryContents.filter{ $0.pathExtension == "mp3" }
    let mp3FileNames = mp3Files.map { $0.deletingPathExtension().lastPathComponent }

    // do not use let, that will create a new variable, just the name of the constant is enough
    downloads = mp3FileNames

} catch {
    // you have to initialize the downloads constant in this control flow branch too, therefore here we assign nil to it
    downloads = nil

    print(error.localizedDescription)
}

// work with downloads
print(downloads)

Upvotes: 0

vadian
vadian

Reputation: 285072

First of all there is a rule:

A variable is only visible in the scope where it has been declared (scope are the pair of braces) and its subscopes.

The local variable

let downloads = mp3FileNames

is declared in the do block so it is not the same object as the variable with the same name on the top level. A local declared variable hides a variable with the same name on a higher level.

There are two other major issues.

  • The variable on the higher level is declared as optional constant. You can't change it!
  • The variable on the higher level is declared as String while mp3FileNames is an array of strings.

If both downloads were the same object you would get compiler errors about those issues.


Solution:

Declare the variable on the higher level as empty array of string

var downloads = [String]()

and assign mp3FileNames to this variable by removing the let keyword

downloads = mp3FileNames

Upvotes: 2

tereks
tereks

Reputation: 1298

First declare global String var

var downloads: String?
let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

Then use func to get all fileNames with mp3 extension

func fileNames() -> String {
    if let directoryContents = try? FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: []) {
        let mp3Files = directoryContents.filter{ $0.pathExtension == "mp3" }
        let mp3FileNames = mp3Files.map{ $0.deletingPathExtension().lastPathComponent }
        return mp3FileNames.joined(separator: ", ")
    }
    return ""
}

And finally

downloads = fileNames()

Upvotes: 0

Related Questions