Swift代码执行顺序。对于方法

时间:2017-11-09 10:10:52

标签: ios arrays swift for-loop methods

我有以下代码下载一些图像,将它们复制到[UIImage]数组中,然后我应该从它们创建视图:

class ViewControllerGallery: UIViewController {

    @IBOutlet weak var  m_loader:UIActivityIndicatorView?

    var m_num_images:Int = 0
    var m_total_images:Int = 0

    var m_str_json:String = ""

    var m_images = [UIImage]()

    var m_views = [UIImageView]()




    override func viewDidLoad() {
        super.viewDidLoad()

        // BEGIN-CODE--4
        self.m_loader?.startAnimating()

        let jsonArray = jsonToArray(jsonString: m_str_json) //implementation of this function was omited for my post


        if let _ = jsonArray {
            m_total_images = (jsonArray?.count)!
        }

        for url in jsonArray! {
            OpenImage(str_url: url)

        }

        if m_total_images != m_num_images {
            print("the function finished without loading all images!")
        } else {
            self.m_loader?.stopAnimating()
        }



    }


    func CreateViews()
    {

        print("createViews was called :) ")

    }




    func OpenImage(str_url:String) {

        let url:URL = URL(string: str_url)!

        getDataFromUrl(url: url){ data, response, error in
            guard let data = data, error == nil else {return}
            DispatchQueue.main.async {
                let image = UIImage(data: data)
                print(image!)


                self.m_images.append(image!)
                print(self.m_images.count)
                self.m_num_images += 1
            }
        }

        //2.3.3 Crear vistas cuando se han cargado todas las imagenes
        print(self.m_total_images == self.m_num_images)
        if self.m_total_images == self.m_num_images {
            print("se igualan las imagenes")
            self.performSelector(onMainThread: #selector(CreateViews), with: nil, waitUntilDone: false)
        }


    }



    //Funciones auxiilares



    func getDataFromUrl(url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
        URLSession.shared.dataTask(with: url) { data, response, error in
            completion(data, response, error)
            }.resume()
    }

}

我希望从视图运行的代码确实加载,当它调用函数OpenImage到达行时,它应该执行OpenImage()中包含的整个代码。如果我运行它,控制台会显示(感谢print()语句)它会奇怪地前后跳转:

false
false
false
the function finished without loading all images!
<UIImage: 0x60c0000afc00>, {1024, 725}
1
<UIImage: 0x60c0000afcc0>, {960, 720}
2
<UIImage: 0x60c0000afc60>, {640, 801}
3

我希望它首先下载所有图像并将它们附加到m_images数组中。然后它应该执行performSelector方法并完成。

出于某种原因,正如你所看到的,它首先跳转到print语句,在那里它将加载的图像数量与图像总数进行比较,它会执行三次,然后它会超出for语句并打印“功能完成而不加载所有图像“然后它再次进入for循环并实际加载图像!为什么?如何以正确的顺序使其工作?

顺便说一下,我知道我应该使用camelCase,但是我已经收到了使用snake_case的类。

2 个答案:

答案 0 :(得分:1)

您正在循环中调用OpenImages,它会进行异步调用。为了使循环能够正确地等待每次迭代返回,您可以在this post中完美地使用调度组。

您的代码应如下所示:

override func viewDidLoad() {
    super.viewDidLoad()
    // Some code...

    let myGroup = DispatchGroup()
    for url in jsonArray! {
        myGroup.enter()
        let url:URL = URL(string: str_url)!
        // You can cut your OpenImages in two
        // here we keep the part that has the async call
        getDataFromUrl(url: url){ data, response, error in
            guard let data = data, error == nil else {return}
            DispatchQueue.main.async {
                let image = UIImage(data: data)
                print(image!)
                self.m_images.append(image!)
                print(self.m_images.count)
                self.m_num_images += 1
                myGroup.leave()
            }
        }
    }

    myGroup.notify(queue: .main) {
        // All the async call have finished
        // Here you can finish what you started in OpenImages()
        // and the rest of your code: "if m_total_images != m_num_images"
    }

}

答案 1 :(得分:0)

那是因为您正在调用异步API(函数)

getDataFromUrl(url: url)

异步API通常是那些需要更多时间来完成任务的网络功能。所以你的代码不会停在这一行。否则,您的UI将被此行阻止,这会提供较差的用户体验。而不是等待“getDataFromUrl”完成其工作,然后执行下一行代码。调用异步API可让您立即执行下一行。当“getDataFromUrl”最终完成其任务时,则执行下面的回调块

guard let data = data, error == nil else {return}
            DispatchQueue.main.async {
                let image = UIImage(data: data)
                print(image!)


                self.m_images.append(image!)
                print(self.m_images.count)
                self.m_num_images += 1
            }