ASMultiplexImageNode.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //
  2. // ASMultiplexImageNode.h
  3. // AsyncDisplayKit
  4. //
  5. // Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
  6. // This source code is licensed under the BSD-style license found in the
  7. // LICENSE file in the root directory of this source tree. An additional grant
  8. // of patent rights can be found in the PATENTS file in the same directory.
  9. //
  10. #import <AsyncDisplayKit/ASImageNode.h>
  11. #import <AsyncDisplayKit/ASImageProtocols.h>
  12. #import <Photos/Photos.h>
  13. NS_ASSUME_NONNULL_BEGIN
  14. @protocol ASMultiplexImageNodeDelegate;
  15. @protocol ASMultiplexImageNodeDataSource;
  16. typedef id<NSCopying, NSObject> ASImageIdentifier;
  17. extern NSString *const ASMultiplexImageNodeErrorDomain;
  18. /**
  19. * ASMultiplexImageNode error codes.
  20. */
  21. typedef NS_ENUM(NSUInteger, ASMultiplexImageNodeErrorCode) {
  22. /**
  23. * Indicates that the data source didn't provide a source for an image identifier.
  24. */
  25. ASMultiplexImageNodeErrorCodeNoSourceForImage = 0,
  26. /**
  27. * Indicates that the best image identifier changed before a download for a worse identifier began.
  28. */
  29. ASMultiplexImageNodeErrorCodeBestImageIdentifierChanged,
  30. /**
  31. * Indicates that the Photos framework returned no image and no error.
  32. * This may happen if the image is in iCloud and the user did not specify `allowsNetworkAccess`
  33. * in their image request.
  34. */
  35. ASMultiplexImageNodeErrorCodePhotosImageManagerFailedWithoutError,
  36. /**
  37. * Indicates that the image node could not retrieve the PHAsset for a given asset identifier.
  38. * This typically means that the user has not given Photos framework permissions yet or the asset
  39. * has been removed from the device.
  40. */
  41. ASMultiplexImageNodeErrorCodePHAssetIsUnavailable
  42. };
  43. /**
  44. * @abstract ASMultiplexImageNode is an image node that can load and display multiple versions of an image. For
  45. * example, it can display a low-resolution version of an image while the high-resolution version is loading.
  46. *
  47. * @discussion ASMultiplexImageNode begins loading images when its resource can either return a UIImage directly, or a URL the image node should load.
  48. */
  49. @interface ASMultiplexImageNode : ASImageNode
  50. /**
  51. * @abstract The designated initializer.
  52. * @param cache The object that implements a cache of images for the image node.
  53. * @param downloader The object that implements image downloading for the image node.
  54. * @discussion If `cache` is nil, the receiver will not attempt to retrieve images from a cache before downloading them.
  55. * @return An initialized ASMultiplexImageNode.
  56. */
  57. - (instancetype)initWithCache:(nullable id<ASImageCacheProtocol>)cache downloader:(nullable id<ASImageDownloaderProtocol>)downloader NS_DESIGNATED_INITIALIZER;
  58. /**
  59. * @abstract The delegate, which must conform to the <ASMultiplexImageNodeDelegate> protocol.
  60. */
  61. @property (nonatomic, readwrite, weak) id <ASMultiplexImageNodeDelegate> delegate;
  62. /**
  63. * @abstract The data source, which must conform to the <ASMultiplexImageNodeDataSource> protocol.
  64. * @discussion This value is required for ASMultiplexImageNode to load images.
  65. */
  66. @property (nonatomic, readwrite, weak) id <ASMultiplexImageNodeDataSource> dataSource;
  67. /**
  68. * @abstract Whether the receiver should download more than just its highest-quality image. Defaults to NO.
  69. *
  70. * @discussion ASMultiplexImageNode immediately loads and displays the first image specified in <imageIdentifiers> (its
  71. * highest-quality image). If that image is not immediately available or cached, the node can download and display
  72. * lesser-quality images. Set `downloadsIntermediateImages` to YES to enable this behaviour.
  73. */
  74. @property (nonatomic, readwrite, assign) BOOL downloadsIntermediateImages;
  75. /**
  76. * @abstract An array of identifiers representing various versions of an image for ASMultiplexImageNode to display.
  77. *
  78. * @discussion An identifier can be any object that conforms to NSObject and NSCopying. The array should be in
  79. * decreasing order of image quality -- that is, the first identifier in the array represents the best version.
  80. *
  81. * @see <downloadsIntermediateImages> for more information on the image loading process.
  82. */
  83. @property (nonatomic, readwrite, copy) NSArray<ASImageIdentifier> *imageIdentifiers;
  84. /**
  85. * @abstract Notify the receiver SSAA that its data source has new UIImages or NSURLs available for <imageIdentifiers>.
  86. *
  87. * @discussion If a higher-quality image than is currently displayed is now available, it will be loaded.
  88. */
  89. - (void)reloadImageIdentifierSources;
  90. /**
  91. * @abstract The identifier for the last image that the receiver loaded, or nil.
  92. *
  93. * @discussion This value may differ from <displayedImageIdentifier> if the image hasn't yet been displayed.
  94. */
  95. @property (nullable, nonatomic, readonly) ASImageIdentifier loadedImageIdentifier;
  96. /**
  97. * @abstract The identifier for the image that the receiver is currently displaying, or nil.
  98. */
  99. @property (nullable, nonatomic, readonly) ASImageIdentifier displayedImageIdentifier;
  100. /**
  101. * @abstract If the downloader implements progressive image rendering and this value is YES progressive renders of the
  102. * image will be displayed as the image downloads. Regardless of this properties value, progress renders will
  103. * only occur when the node is visible. Defaults to YES.
  104. */
  105. @property (nonatomic, assign, readwrite) BOOL shouldRenderProgressImages;
  106. #if TARGET_OS_IOS
  107. /**
  108. * @abstract The image manager that this image node should use when requesting images from the Photos framework. If this is `nil` (the default), then `PHImageManager.defaultManager` is used.
  109. * @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below.
  110. */
  111. @property (nullable, nonatomic, strong) PHImageManager *imageManager;
  112. #endif
  113. @end
  114. #pragma mark -
  115. /**
  116. * The methods declared by the ASMultiplexImageNodeDelegate protocol allow the adopting delegate to respond to
  117. * notifications such as began, progressed and finished downloading, updated and displayed an image.
  118. */
  119. @protocol ASMultiplexImageNodeDelegate <NSObject>
  120. @optional
  121. /**
  122. * @abstract Notification that the image node began downloading an image.
  123. * @param imageNode The sender.
  124. * @param imageIdentifier The identifier for the image that is downloading.
  125. */
  126. - (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode didStartDownloadOfImageWithIdentifier:(id)imageIdentifier;
  127. /**
  128. * @abstract Notification that the image node's download progressed.
  129. * @param imageNode The sender.
  130. * @param downloadProgress The progress of the download. Value is between 0.0 and 1.0.
  131. * @param imageIdentifier The identifier for the image that is downloading.
  132. */
  133. - (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode
  134. didUpdateDownloadProgress:(CGFloat)downloadProgress
  135. forImageWithIdentifier:(ASImageIdentifier)imageIdentifier;
  136. /**
  137. * @abstract Notification that the image node's download has finished.
  138. * @param imageNode The sender.
  139. * @param imageIdentifier The identifier for the image that finished downloading.
  140. * @param error The error that occurred while downloading, if one occurred; nil otherwise.
  141. */
  142. - (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode
  143. didFinishDownloadingImageWithIdentifier:(ASImageIdentifier)imageIdentifier
  144. error:(nullable NSError *)error;
  145. /**
  146. * @abstract Notification that the image node's image was updated.
  147. * @param imageNode The sender.
  148. * @param image The new image, ready for display.
  149. * @param imageIdentifier The identifier for `image`.
  150. * @param previousImage The old, previously-loaded image.
  151. * @param previousImageIdentifier The identifier for `previousImage`.
  152. * @note This method does not indicate that `image` has been displayed.
  153. * @see <[ASMultiplexImageNodeDelegate multiplexImageNode:didDisplayUpdatedImage:withIdentifier:]>.
  154. */
  155. - (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode
  156. didUpdateImage:(nullable UIImage *)image
  157. withIdentifier:(nullable ASImageIdentifier)imageIdentifier
  158. fromImage:(nullable UIImage *)previousImage
  159. withIdentifier:(nullable ASImageIdentifier)previousImageIdentifier;
  160. /**
  161. * @abstract Notification that the image node displayed a new image.
  162. * @param imageNode The sender.
  163. * @param image The new image, now being displayed.
  164. * @param imageIdentifier The identifier for `image`.
  165. * @discussion This method is only called when `image` changes, and not on subsequent redisplays of the same image.
  166. */
  167. - (void)multiplexImageNode:(ASMultiplexImageNode *)imageNode
  168. didDisplayUpdatedImage:(nullable UIImage *)image
  169. withIdentifier:(nullable ASImageIdentifier)imageIdentifier;
  170. /**
  171. * @abstract Notification that the image node finished displaying an image.
  172. * @param imageNode The sender.
  173. * @discussion This method is called every time an image is displayed, whether or not it has changed.
  174. */
  175. - (void)multiplexImageNodeDidFinishDisplay:(ASMultiplexImageNode *)imageNode;
  176. @end
  177. #pragma mark -
  178. /**
  179. * The ASMultiplexImageNodeDataSource protocol is adopted by an object that provides the multiplex image node,
  180. * for each image identifier, an image or a URL the image node should load.
  181. */
  182. @protocol ASMultiplexImageNodeDataSource <NSObject>
  183. @optional
  184. /**
  185. * @abstract An image for the specified identifier.
  186. * @param imageNode The sender.
  187. * @param imageIdentifier The identifier for the image that should be returned.
  188. * @discussion If the image is already available to the data source, this method should be used in lieu of providing the
  189. * URL to the image via -multiplexImageNode:URLForImageIdentifier:.
  190. * @return A UIImage corresponding to `imageIdentifier`, or nil if none is available.
  191. */
  192. - (nullable UIImage *)multiplexImageNode:(ASMultiplexImageNode *)imageNode imageForImageIdentifier:(ASImageIdentifier)imageIdentifier;
  193. /**
  194. * @abstract An image URL for the specified identifier.
  195. * @param imageNode The sender.
  196. * @param imageIdentifier The identifier for the image that will be downloaded.
  197. * @discussion Supported URLs include HTTP, HTTPS, AssetsLibrary, and FTP URLs as well as Photos framework URLs (see note).
  198. *
  199. * If the image is already available to the data source, it should be provided via <[ASMultiplexImageNodeDataSource
  200. * multiplexImageNode:imageForImageIdentifier:]> instead.
  201. * @return An NSURL for the image identified by `imageIdentifier`, or nil if none is available.
  202. * @see `+[NSURL URLWithAssetLocalIdentifier:targetSize:contentMode:options:]` below.
  203. */
  204. - (nullable NSURL *)multiplexImageNode:(ASMultiplexImageNode *)imageNode URLForImageIdentifier:(ASImageIdentifier)imageIdentifier;
  205. #if TARGET_OS_IOS
  206. /**
  207. * @abstract A PHAsset for the specific asset local identifier
  208. * @param imageNode The sender.
  209. * @param assetLocalIdentifier The local identifier for a PHAsset that this image node is loading.
  210. *
  211. * @discussion This optional method can improve image performance if your data source already has the PHAsset available.
  212. * If this method is not implemented, or returns nil, the image node will request the asset from the Photos framework.
  213. * @note This method may be called from any thread.
  214. * @return A PHAsset corresponding to `assetLocalIdentifier`, or nil if none is available.
  215. */
  216. - (nullable PHAsset *)multiplexImageNode:(ASMultiplexImageNode *)imageNode assetForLocalIdentifier:(NSString *)assetLocalIdentifier;
  217. #endif
  218. @end
  219. #pragma mark -
  220. #if TARGET_OS_IOS
  221. @interface NSURL (ASPhotosFrameworkURLs)
  222. /**
  223. * @abstract Create an NSURL that specifies an image from the Photos framework.
  224. *
  225. * @discussion When implementing `-multiplexImageNode:URLForImageIdentifier:`, you can return a URL
  226. * created by this method and the image node will attempt to load the image from the Photos framework.
  227. * @note The `synchronous` flag in `options` is ignored.
  228. * @note The `Opportunistic` delivery mode is not supported and will be treated as `HighQualityFormat`.
  229. */
  230. + (NSURL *)URLWithAssetLocalIdentifier:(NSString *)assetLocalIdentifier
  231. targetSize:(CGSize)targetSize
  232. contentMode:(PHImageContentMode)contentMode
  233. options:(PHImageRequestOptions *)options AS_WARN_UNUSED_RESULT;
  234. @end
  235. #endif
  236. NS_ASSUME_NONNULL_END