Swift 连续发出多个异步HTTP请求并使用Realm写入

Swift 连续发出多个异步HTTP请求并使用Realm写入,swift,watchkit,realm,alamofire,Swift,Watchkit,Realm,Alamofire,我目前正在使用Alamofire请求数据,并将数据写入带有Realm的磁盘。具体来说,我从Facebook Graph GET请求中获取24个源URL,然后分别发出24个请求来检索每个图像的数据。一旦检索到数据,我将使用Realm写入磁盘 以下是我获取24个来源的方法: FBAPI Alamofire.request(.GET, FBPath.photos, parameters: params).responseJSON { response in guard resp

我目前正在使用Alamofire请求数据,并将数据写入带有Realm的磁盘。具体来说,我从Facebook Graph GET请求中获取24个源URL,然后分别发出24个请求来检索每个图像的数据。一旦检索到数据,我将使用Realm写入磁盘

以下是我获取24个来源的方法:

FBAPI

Alamofire.request(.GET, FBPath.photos, parameters: params).responseJSON { response in
            guard response.result.error == nil else {
                print("error calling GET on \(FBPath.photos)")
                print(response.result.error!)
                completion(latestDate: nil, photosCount: 0, error: response.result.error)
                return
            }
            if let value = response.result.value {
                let json = JSON(value)
                if let photos = json[FBResult.data].array {
                    for result in photos {
                        let manager = PTWPhotoManager()
                        manager.downloadAndSaveJsonData(result)
                    }
如您所见,我有一个for循环,循环遍历每个JSON,其中包含照片图像的源url,然后对每个url发出另一个网络请求,如下所示:

经理

func downloadAndSaveJsonData(photoJSON : JSON) {

        let source = photoJSON[FBResult.source].string
        let id = photoJSON[FBResult.id].string
        let created_time = photoJSON[FBResult.date.createdTime].string
        let imageURL = NSURL(string: source!)

        print("image requested")
        Alamofire.request(.GET, imageURL!).response() {
            (request, response, data, error) in
            if (error != nil) {
                print(error?.localizedDescription)
            }
            else {
                print("image response")
                let photo = PTWPhoto()
                photo.id = id
                photo.sourceURL = source
                photo.imageData = data
                photo.createdTime = photo.createdTimeAsDate(created_time!)
                let realm = try! Realm()
                try! realm.write {
                    realm.add(photo)
                }
                print("photo saved")
            }
        }
    }

在请求每个图像的数据和收到响应之间似乎有很长的延迟,而且它似乎也不是异步的。这是线程问题还是有更有效的方法来请求这样的数据数组?还应该注意的是,我是从苹果手表本身发出这个网络请求的

这些请求将按照您的意愿以异步方式进行。但是发生了一些同步,您可能不知道:

  • Alamofire的响应闭包被调度到主线程。因此,您的网络响应将与您所做的任何UI更新竞争
  • 领域写入事务是同步的和排他的,这是通过锁强制的,锁将阻止执行它们的线程
  • 这两者的结合意味着,只要网络请求成功并持续出现,你就会阻塞主线程,这也会使你的应用程序没有响应

    我推荐另一种尝试。您可以使用GCD的调度组来同步不同的异步任务

    在下面的示例中,对象都保存在内存中,直到它们全部下载

    进一步的改进可能是将下载的数据写入磁盘,并将文件路径存储在领域对象中。(有很多图像缓存库,可以很容易地为您提供帮助。)

    如果您选择的路径仅取决于
    PWTPhoto
    的字段(或数据的属性,您可以通过快速HEAD请求获得),则可以在再次下载文件之前,首先检查此路径是否已在本地存在。通过这样做,您可以在更新照片或首次尝试时无法成功下载所有照片时节省流量。(例如,应用程序被用户强制关闭、崩溃、设备关闭)


    在手表上进行这些抓取是非常不切实际的,因为当手表进入睡眠状态时,手表应用程序将被暂停。您应该让手机预取图像,并将它们发送到后台的手表,这样当手表应用程序打开时,最近的图像就可以立即使用。@PetahChristian true,我计划将来结合使用网络请求和后台传输。但是,这种获取方法在电话上实用吗?特别是列举的网络请求?谢谢。我感谢你的答复。
    class PTWPhotoManager {
    
        static func downloadAllPhotos(params: [String : AnyObject], completion: (latestDate: NSDate?, photosCount: NSUInteger, error: NSError?)) {
            Alamofire.request(.GET, FBPath.photos, parameters: params).responseJSON { response in
                guard response.result.error == nil else {
                    print("error calling GET on \(FBPath.photos)")
                    print(response.result.error!)
                    completion(latestDate: nil, photosCount: 0, error: response.result.error)
                    return
                }
                if let value = response.result.value {
                    let json = JSON(value)
                    if let photos = json[FBResult.data].array {
                        let group = dispatch_group_create()
                        var persistablePhotos = [PTWPhoto](capacity: photos.count)
                        let manager = PTWPhotoManager()
                        for result in photos {
                            dispatch_group_enter(group)
                            let request = manager.downloadAndSaveJsonData(result) { photo, error in
                                if let photo = photo {
                                    persistablePhotos.add(photo)
                                    dispatch_group_leave(group)
                                } else {
                                    completion(latestDate: nil, photosCount: 0, error: error!)
                                }
                            }
                        }
    
                        dispatch_group_notify(group, dispatch_get_main_queue()) {
                            let realm = try! Realm()
                            try! realm.write {
                                realm.add(persistablePhotos)
                            }
                            let latestDate = …
                            completion(latestDate: latestDate, photosCount: persistablePhotos.count, error: nil)
                        }
                    }
                }
            }
        }
    
        func downloadAndSaveJsonData(photoJSON: JSON, completion: (PTWPhoto?, NSError?) -> ()) -> Alamofire.Request {
            let source = photoJSON[FBResult.source].string
            let id = photoJSON[FBResult.id].string
            let created_time = photoJSON[FBResult.date.createdTime].string
            let imageURL = NSURL(string: source!)
    
            print("image requested")
            Alamofire.request(.GET, imageURL!).response() { (request, response, data, error) in
                if let error = error {
                    print(error.localizedDescription)
                    completion(nil, error)
                } else {
                    print("image response")
                    let photo = PTWPhoto()
                    photo.id = id
                    photo.sourceURL = source
                    photo.imageData = data
                    photo.createdTime = photo.createdTimeAsDate(created_time!)
                    completion(photo, nil)
                }
            }
        }
    
    }