Ground of Being:这将有助于在阅读之前了解您无法通过键路径image
将UIImage分配给图像视图插座的\UIImageView.image
属性。这是属性:
@IBOutlet weak var iv: UIImageView!
现在,可以编译吗?
let im = UIImage()
let kp = \UIImageView.image
self.iv[keyPath:kp] = im // error
不!
可选类型'UIImage的值?必须解压为'UIImage'类型的值]
好,现在我们可以开始实际使用了。
我实际上想了解的是Combine框架.assign
订户在后台如何工作。为了进行实验,我尝试使用自己的Assign对象。在我的示例中,我的发布者管道生成一个UIImage对象,并将其分配给UIImageView属性image
的self.iv
属性。
如果使用.assign
方法,则可以编译并运行:
URLSession.shared.dataTaskPublisher(for: url) .map {$0.data} .replaceError(with: Data()) .compactMap { UIImage(data:$0) } .receive(on: DispatchQueue.main) .assign(to: \.image, on: self.iv) .store(in:&self.storage)
因此,我对自己说,要了解其工作原理,我将删除
.assign
并将其替换为我自己的Assign对象:let pub = URLSession.shared.dataTaskPublisher(for: url) .map {$0.data} .replaceError(with: Data()) .compactMap { UIImage(data:$0) } .receive(on: DispatchQueue.main) let assign = Subscribers.Assign(object: self.iv, keyPath: \UIImageView.image) pub.subscribe(assign) // error // (and we will then wrap in AnyCancellable and store)
拍手!我们不能这样做,因为
UIImageView.image
是一个可选的UIImage,而我的发布者生成的UIImage简单明了。我试图通过在密钥路径中展开Optional来解决此问题:
如何工作?我的意思是,为什么我不必在使用let assign = Subscribers.Assign(object: self.iv, keyPath: \UIImageView.image!) pub.subscribe(assign)
很酷,可以编译。但是它在运行时崩溃,可能是因为图像视图的图像最初是
nil
。现在,我可以通过在管道中添加
map
来解决所有这些问题,该管道将UIImage包裹在Optional中,以便所有类型都正确匹配。但是我的问题是,这really
.assign
的第一个代码中这样做?为什么我可以在那里指定.image
键路径?关键路径如何与Optional属性一起使用似乎有些技巧,但我不知道它是什么。[从Martin R输入一些信息后,我意识到,如果在生成pub
时显式键入UIImage?
,我们将获得与添加map
并将UIImage包装在Optional中的效果相同的效果。这样就可以编译工作了
传递到let pub : AnyPublisher<UIImage?,Never> = URLSession.shared.dataTaskPublisher(for: url) .map {$0.data} .replaceError(with: Data()) .compactMap { UIImage(data:$0) } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() let assign = Subscribers.Assign(object: self.iv, keyPath: \UIImageView.image) pub.subscribe(assign) let any = AnyCancellable(assign) any.store(in:&self.storage)
这仍然不能解释原始
的可选性push.assign
的工作原理。看来,可以将类型up
.receive
运算符中。但是我不知道怎么可能。存在的基础:在阅读之前,这将有助于您不能通过键路径\ UIImageView.image将UIImage分配给图像视图插座的image属性。这是属性:@IBOutlet ...
我不会回答这个问题:
这仍然不能解释原始
.assign
的工作原理。