RxSwift responsive programming actual observation sequence

The architecture design of a series of MVC MVVM from -> -> MVP -> Router -> Downgradable, we will be through the implementation of hierarchical and dynamic decoupling of each component and the page, this series of ready to talk about how to respond better programming and architecture design are coordinated by RxSwift. Code: GitHub

RxSwift responsive programming actual observation sequence

This series is the case notes by Ray’s book RxSwift, before studying this article, please ensure that master the basic grammar Swift3 and intermediate iOS development. The RxSwift concept is not very clear of the students can refer to the code in this article playground in advance do not understand the familiar, please refer to the summary, in order to a better understanding of this paper.

First we need to introduce cocapods through RxSwift:

The next line to # Uncomment define a global platform for your project platform IOS,'10.0'target'AlbumPuzzle': do the next line if # Comment you're not using Swift and don't want to use dynamic frameworks use_frameworks Pods for AlbumPuzzle pod #!'RxSwift','~> 3.2''~> pod'RxCocoa', 3.2' end
RxSwift responsive programming actual observation sequence

We need to add some necessary controls, avoid too much code, we can pass the StoryBoard to carry on the View layer of the first page layout, we need four controls: display pictures, add button, reset button, save button. The second page is a simple CollectoinViewController.

Class ViewController: UIViewController weak var imagePreview: {@IBOutlet UIImageView @IBOutlet weak var buttonClear:! UIButton! @IBOutlet weak var buttonSave: UIButton @IBOutlet weak var itemAdd:! UIBarButtonItem! Fileprivate let bag DisposeBag (fileprivate) let = images = Variable< [UIImage]> override func viewDidLoad ([]) ((setupObservable)) {super.viewDidLoad}} {(extension) ViewController fileprivate func (setupObservable) {images.asObservable (.Subscribe) (onNext: [weak self] images in guard {let preview = self?.imagePreview else {return} preview.image = UIImage.collage (images: images, size: preview.frame.size.AddDisposableT)}) O (bag) (images.asObservable).Subscribe (onNext: [weak self] images in self {.UpdateUI} (images:? Images).AddDisposableTo (bag) fileprivate func updateUI (images:)} [UIImage]) {buttonSave.isEnabled = images.count > & & amp; 0; images.count% 2 = = 0 buttonClear.isEnabled = images.count > = 0; itemAdd.isEnabled images.count < 6 title = images.count > 0? "/ (images.count) photos": "Collage"}} extension {ViewController @IBAction func (actionAdd) {images.value.append (UIImage ("named: Castie!")!}) @IBAction func (actionClear) {images.value = @IBAction (func actionSave) []} {}}

We enter ViewController, create two private variable, bag, is a DisposeBag example, images is a generic Variable for DisposeBag and Variable do not understand please in advance access to the contents of the playground code extension partition via the syntax of Swift decorative pattern, by adding the changes happened to subscribe monitoring images array images, and to operate the button click. In order to achieve better results, the need to introduce the classification of UIImage+Collage.

RxSwift responsive programming actual observation sequence

So we can achieve a simple response programming, when the subscriber value is changed, it will update the operation. KVO is similar to the monitoring effect. Because iOS10 start mechanism for accessing the user information has been updated, users need to access the album in this case, so the following configuration in info.plist:
Privacy – Photo Library Usage Description, We need access to your device’s photo library to allow you to select photos for your collage.

To complete the configuration, we will go through the Photos system framework for the system to get pictures in the album, of course, you can also use UIImagePickerController, predict how to use click!

Import UIKit import Photos import RxSwift private let reuseIdentifier = "Cell" class AlbumViewController: UICollectionViewController (DisposeBag) {let bag = var selectedImages: Observable< UIImage> selectedImagesSubject.asObservable) {return} (fileprivate let = selectedImagesSubject PublishSubject< UIImage> lazy var images (fileprivate) = AlbumViewController.loadImages (fileprivate) lazy var imageManager (fileprivate) = PHCachingImageManager lazy var thumbnailSize: CGSize = {let = cellSize (self.collectionViewLayout as UICollectionViewFlowLayout.ItemSize return CGSize (!) width: cellSize.width * UIScreen.main.scale, height: * UIScreen. cellSize.height Main.scale func (override))} (viewDidLoad) {super.viewDidLoad (self.collectionView).Register (UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier! Extension AlbumViewController static})} {func (loadImages) -> PHFetchResult< PHAsset> allImagesOptions) {let = PHFetchOptions (allImagesOptions.sortDescriptors = [NSSortDescriptor (key: creationDate, ascending: true return PHAsset.fetchAssets allImagesOptions (with:)] extension {override})} AlbumViewController (func collectionView collectionView: UICollectionView numberOfItemsInSection section: Int _, -> Int) {return images.count} override func collectionView (collectionV _ Iew: UICollectionView, cellForItemAt indexPath: IndexPath -> UICollectionViewCell) {let asset = images.object (at: indexPath.item) let cell = collectionView.dequeueReusableCell (withReuseIdentifier: reuseIdentifier, for: indexPath imageManager.requestImage (for:) asset, targetSize: thumbnailSize, contentMode:.AspectFill, options: nil, resultHandler: in _ {image, cell.layer.contents = image?.cgImage return cell override func})} (collectionView _ collectionView: UICollectionView didSelectItemAt, indexPath: IndexPath) {let asset = images.object (at: indexPath.item) if let cell = collectionView.cellForItem (at: indexPath) {cell.alpha = 0 UIView.animate (withDuration: 0.5, animations: cell.alpha = {1})} imageManager.requestImage (for: asset, targetSize: view.frame.size, contentMode:.AspectFill, options: nil, resultHandler: self] info in {[weak image, guard let image = image, let = Info Info else {return} if let isThumbnail = info[PHImageResultIsDegradedKey as NSString] as? Bool, isThumbnail {self!.selectedImagesSubject.onNext? (image)}})}}

Here is a brief description of the Photos system framework, Photos framework is a new picture of the framework provided by Apple iOS8, direct access to pictures and videos, including iCloud above the gallery. Use this framework to get assets to display and playback, edit pictures or video content, or use the system album, moments, and share the iCloud album to do the relevant operation

We have used PHCachingImageManager, PHFetchResult, PHFetchOptions, PHAsset

PHCachingImageManager is a subclass of PHImageManager, if there are a large number of pictures, and you need to quickly get the thumbnail image and image data for display, this time can be achieved by PHCachingImageManager, it has the caching mechanism can be quickly obtained an atlas thumbnail in the background or to request the full size image quick display.

Many will call'resultHandler'/ * * *, first call, return the low resolution images, when high definition picture can be obtained, will call again, if the high quality pictures in the cache exchange, only one call to'resultHandler'. The method of default is asynchronous, as from a background thread to call this method when you need to options the'synchronous'to YES. * * @param asset asset * @param save the image information returned by the targetSize @param contentMode picture size * return picture display mode * @ param options image request option @param resultHandler * * * to return the content @return request for marking, cancel the request func / open requestImage (for asset: PHAsset, targetSize: CGSize, contentMode: PHImageContentMode, options: PHImageRequestOptions, resultHandler:? @escaping (UIImage? [AnyHashable, Any]?) -> Swift.Void -> PHImageRequestID)

PHFetchResult is a container ordered photo object contains, returned by the retrieval conditions are given for asset, photo album, photo album album a list of all types in (for example, all albums, smart album type of it is ordered), in PHAsset, PHCollection, PHAssetcollection, PHCollectionList these are included in the corresponding class the method contains the corresponding information of the PHFetchRequest object, for example:

Open class func (with options: PHFetchOptions?) -> PHFetchResult< PHAsset> fetchAssets;

When you don’t use PHFetchOptions: method to obtain PHAsset (image and video), PHCollection (album type), PHAssetCollection (Album) entity (equivalent to contain more than one data model) using the specified PHFetchOptions object operation, such as getting the entity attribute row column.

This operation is very simple, is to visit the PHFetchOptions PHFetchResult specific options in PHAsset and use the PHCachingImageManager to request the system to obtain the corresponding album pictures and show the way through boarding map to the Cell.

RxSwift responsive programming actual observation sequence

The key to our response programming is the following code in the Cell click function:

If let isThumbnail = NSString] as? Bool, isThumbnail {self?.selectedImagesSubject.onNext (image)} () as

Send the data to the subscriber by publishing the onNext method of the object PublishSubject, and back to ViewController, we update some of the code:

@IBAction func (actionAdd) {/ / images.value.append (UIImage ("named: Castie!")!) let albumViewController = storyboard?.instantiateViewController (withIdentifier: AlbumViewController AlbumViewController albumViewController.selectedImages.subscribe (onNext:) as! [weak self] newImage in guard {let images = self?.images else images.value.append (newImage) {return}}, {print ("onDisposed: completed photo selection.AddDisposableTo)}") (albumViewController.bag) navigationController?.pushViewController (albumViewController, animated: true)}

In this way we achieved through the RxSwift response between the pages of the interaction, and then we will achieve the image of the save operation:

Class AlbumWriter: NSObject {typealias = Callback (NSError? ->); Void private var callback: Callback private init (callback: @escaping Callback) {self.callback} = callback func image (image: UIImage didFinishSavingWithError error: _, NSError? ContextInfo:, UnsafeRawPointer) {callback} (error) static func save (image: UIImage _) -> Observable< Void> {return {observer (Observable.create; in let writer = AlbumWriter (callback: error in if let {error = error {observer.onError} else {(error)}} (observer.onCompleted) UIImageWriteToSavedPhotosAlbum (image), Writer, #selector (AlbumWriter.image (_: didFinishSavingWithError:contextInfo:), nil return (Disposables.create))))}}}

Encapsulates a picture stored in the AlbumWriter class, the Create method to create the observer

@IBAction func actionSave (let image imagePreview.image) {guard = else {return} AlbumWriter.save (image).Subscribe (onError: [weak self] error in {self?.showMessage (Error, description: error.localizedDescription)}, {[weak onCompleted: self] in self?.showMessage (Saved) self?.actionClear (.AddDisposableTo)}) (bag)}

Finally, when the Save operation when the subscription is done!!

Demonstration effect:

RxSwift responsive programming actual observation sequence


RxSwift responsive programming actual observation sequence
click on the link below jump!!

The source here > > > love friends please love > > > download the source code please send small stars > > > have the money for the trench can a reward > > > I will soon launch a better article to share &gt and everyone; > > your encouragement is my motivation!!