sathish kumar
sathish kumar

Reputation: 89

How to access the variable in a nested loop?

I am trying to access the value of "x" in nested loop but each time i try this the value of "x" in inner loop it gets varied.

var downloads_array = [[URL]]()//edited
func downloadImages(){

        var count = images.count
        let storage = Storage.storage().reference()

        for x in 0...count-1{
            var anime = [String]()
            anime.append(images[x])
            anime.append(images[x] + "1")
            print("outside the second loop x is : \(x)")

            for i in anime{
                let storageRef = storage.child("images/\(i).jpg")
                storageRef.downloadURL { (url, error) in
                    if let error = error{
                        print(error.localizedDescription)
                    }
                    else{
                        print(x)
                        self.downloads_array[x].append(url!)//edited
                    }
                }
            }
        }

    }

The ouput is:

outside the second loop x is : 0
outside the second loop x is : 1
outside the second loop x is : 2
outside the second loop x is : 3
outside the second loop x is : 4
outside the second loop x is : 5
0
3
0
1
1
4
2
5
3
4
2
5

I am new to swift development please guide me in solving this issue.

Upvotes: 0

Views: 409

Answers (4)

sathish kumar
sathish kumar

Reputation: 89

As the Firebase Storage was an Asynchronous call(network call), We can't retain the value as the order will be non-sequential. So i Created a dictionary with String and URL to store the respective download URL for the image

Upvotes: 0

Kuldeep Tanwar
Kuldeep Tanwar

Reputation: 3526

Not sure exactly what you need but I think you're trying to implement something like this : -

func downloadImages(){
    var count = images.count
    let storage = Storage.storage().reference()
    var data : [String:Int] = []
    for x in 0...count-1{
        var anime = [String]()
        anime.append(images[x])
        anime.append(images[x] + "1")
        print("outside the second loop x is : \(x)")

        for i in anime {
            let storageRef = storage.child("images/\(i).jpg")
            data["YourUrl"] = x // Replace YourUrl with your url string
            storageRef.downloadURL { (url, error) in
                if let error = error{
                    print(error.localizedDescription)
                }
                else{
                    if let value = data[url.absoluteString]{
                        print(value)
                    }

                }
            }
        }
    }
}

Upvotes: 1

Francescu
Francescu

Reputation: 17054

storageRef.downloadURL is async so the code will continue executing and x value will change. The solution here is to capture the current x value either through an intermediary variable or though block capture

Block capture

var downloads_array = [[URL]]()//edited
func downloadImages(){

    var count = images.count
    let storage = Storage.storage().reference()

    for x in 0...count-1{
        var anime = [String]()
        anime.append(images[x])
        anime.append(images[x] + "1")
        print("outside the second loop x is : \(x)")

        for i in anime{
            let storageRef = storage.child("images/\(i).jpg")
            storageRef.downloadURL { [x] (url, error) in // block capture
                if let error = error{
                    print(error.localizedDescription)
                }
                else{
                    print(x)
                    self.downloads_array[x].append(url!)//edited
                }
            }
        }
    }

}

 -

Intermediary variable

var downloads_array = [[URL]]()//edited
func downloadImages(){

    var count = images.count
    let storage = Storage.storage().reference()

    for x in 0...count-1{
        var anime = [String]()
        anime.append(images[x])
        anime.append(images[x] + "1")
        print("outside the second loop x is : \(x)")

        for i in anime{
            let storageRef = storage.child("images/\(i).jpg")
            let currentX = x // intermediary variable
            storageRef.downloadURL { (url, error) in
                if let error = error{
                    print(error.localizedDescription)
                }
                else{
                    print(currentX)
                    self.downloads_array[currentX].append(url!)//edited
                }
            }
        }
    }

}

Upvotes: 2

Rakesha Shastri
Rakesha Shastri

Reputation: 11242

Your storageRef.downloadURL is an async call, which means it will take time for the completion block to be executed. The for loop would be executed and count * 2 calls would be hit. Depending on how fast each response is received the appropriate completion is called resulting in the order that you are getting.

func downloadImages(){
    var count = images.count
    let storage = Storage.storage().reference()

    for x in 0...count-1{
        var anime = [String]()
        anime.append(images[x])
        anime.append(images[x] + "1")
        print("outside the second loop x is : \(x)")

        print(x) // printing it here will give you the order as is
        for i in anime {
            let storageRef = storage.child("images/\(i).jpg")
            storageRef.downloadURL { (url, error) in
                if let error = error{
                    print(error.localizedDescription)
                }
                else{
                    print(x)
                }
            }
        }
    }
}

Since you do not have control over the order in which the completion block is executed. A dictionary would be one solution to your problem. Store the index as the key and url array as the value. Or you could have a struct which stores the urls for the corresponding index and sort it.

Upvotes: 2

Related Questions