我正在训练自己使用ReactiveSwift进行联网,一个很好的用例似乎是从Google Places API for iOS获取位置的照片。
流程如下:
GMSPlacePhotoMetadata
从谷歌地点 ID获取列表- 对于每个元数据,获取一张图片
- 将所有图片连接为一个数组
我以我能想到的最好的 ReactiveSwift 方式编写了执行此工作流程的代码(参见下面的代码),但是当我调用我的服务时,尽管对 Google Places API 进行了所有 API 调用,但我并没有进入观察部分。我觉得我在框架中遗漏了一些非常基本的东西,并且在此过程中我失去了一些观察者,但我无法指出问题所在。任何帮助都将受到欢迎。
我的服务代码
import Foundation
import ReactiveSwift
import GooglePlaces
struct GooglePlacesPhotoService {
func findPlacePictures(googlePlaceID: String) -> SignalProducer<[UIImage], DataStoreError> {
return findPlacePicturesMetadata(googlePlaceID: googlePlaceID)
.map { (metadata) -> SignalProducer<UIImage, DataStoreError> in
debugPrint("Mapping metadata to SignalProducer for metadata: ", metadata)
return self.findPlacePicture(metadata: metadata)
} // After mapping, we have a SignalProducer of SignalProducer<UIImage>
.flatten(.merge) // After flatening, we get a single SignalProducer<UIImage>
.reduce([], { (imageArray: [UIImage], newImage: UIImage) -> [UIImage] in
debugPrint("Merging another picture")
return imageArray + [newImage]
}) // Now we have an array of UIImage
}
private func findPlacePicturesMetadata(googlePlaceID: String) -> SignalProducer<GMSPlacePhotoMetadata, DataStoreError> {
return SignalProducer<GMSPlacePhotoMetadata, DataStoreError> { observer, disposable in
GMSPlacesClient.shared().lookUpPhotos(forPlaceID: googlePlaceID) { photos, error in
guard error == nil else { return observer.send(error: .externalError(error!)) }
guard let photos = photos else { return }
photos.results.forEach { metadata in
debugPrint("Sending metadata value: ", metadata)
observer.send(value: metadata)
}
}
}
}
private func findPlacePicture(metadata: GMSPlacePhotoMetadata) -> SignalProducer<UIImage, DataStoreError> {
return SignalProducer<UIImage, DataStoreError> { observer, disposable in
let screenSize = UIScreen.main.bounds.size
let screenScale = UIScreen.main.scale
let myCallback: GMSPlacePhotoImageResultCallback = { image, error in
guard error == nil else {
print("ERROR: couln't load picture for metadata \(metadata)")
observer.send(error: .externalError(error!))
return
}
guard let image = image else {
print("ERROR: empty image returned")
observer.send(error: .unknownExternalError)
return
}
debugPrint("Got 1 picture from metadata: ", metadata)
observer.send(value: image)
}
GMSPlacesClient.shared().loadPlacePhoto(metadata,
constrainedTo: screenSize,
scale: screenScale,
callback: myCallback)
}
}
}
我的观察代码
googlePlaceIDProperty.signal
.filter { $0.isPresent }
.flatMap(.latest) { googlePlaceID in
return GooglePlacesPhotoService().findPlacePictures(googlePlaceID: googlePlaceID!)
}.observe { event in
debugPrint("Signal event!") // I NEVER GET THERE
switch event {
case let .value(pictures):
// Do stuff
case let .failed(error):
// Do stuff
default:
break
}
}
我的日志
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x60000645f4d0>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x60000645f4d0>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x60000645b1b0>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x60000645b1b0>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x60000645b0f0>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x60000645b0f0>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x600006459950>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x600006459950>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x60000644e730>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x60000644e730>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x60000645ef30>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x60000645ef30>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x6000066420a0>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x6000066420a0>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x600006448d60>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x600006448d60>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x600006642130>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x600006642130>
"Sending metadata value: " <GMSPlacePhotoMetadata: 0x6000066421f0>
"Mapping metadata to SignalProducer for metadata: " <GMSPlacePhotoMetadata: 0x6000066421f0>
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x60000645f4d0>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x60000645b1b0>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x60000645b0f0>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x600006459950>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x60000644e730>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x60000645ef30>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x6000066420a0>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x600006448d60>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x600006642130>
"Merging another picture"
"Got 1 picture from metadata: " <GMSPlacePhotoMetadata: 0x6000066421f0>
"Merging another picture"