Open Source Project Analysis (SwiftHub) Rxswift + MVVM + Moya Architecture Analysis (I)

Open Source Project Analysis (SwiftHub) Rxswift + MVVM + Moya Architecture Analysis (II) Use of third-party frameworks (IN)

@[TOC]

2. Third-party library SwiftHub uses

This blog is the sequel of SwiftHub Rxswift + MVVM + Moya Architecture Analysis (a) Third party framework Usage. Due to the length of the process, it is divided into several parts.

Let’s review the third-party framework:

2.1 Rxswift family library

2.1.1 RxAnimated

  • Source code: RxAnimated

RxAnimated

It provides some predefined animation bindings and provides a flexible mechanism for you to add your own predefined animations and use them when binding with RxCocoa.

2.1.1.1 RxAnimatedBasic animation use

  • Built-in animations provided by RxAnimated:

When binding values to RxCocoa, you can write:

textObservable
  .bind(to: labelFlip.rx.text)
Copy the code

Every time an Observable issues a new string value, it updates the text of the tag. But it happened all of a sudden, without any transition. With RxAnimated, you can use the Animated extension to bind values and animations like this:

textObservable
  .bind(animated: labelFlip.rx.animated.flip(.top, duration: 0.33).text)
Copy the code

The “difference is” that you use bind(animated:) instead of bind(to:), and then you insert either animated.flip(.top, duration: 0.33)(or one of the other provided or custom animation methods) between the RX and the property receiver you want to use.

2.1.1.2 RxAnimatedBasic animation list

  • List of built-in animation types:
UIView.rx.animated... isHiddenUIView.rx.animated... alphaUILabel.rx.animated... textUILabel.rx.animated... attributedTextUIControl.rx.animated... isEnabledUIControl.rx.animated... isSelectedUIButton.rx.animated... titleUIButton.rx.animated... imageUIButton.rx.animated... backgroundImageUIImageView.rx.animated... imageNSLayoutConstraint.rx.animated... constantNSLayoutConstraint.rx.animated... isActiveCopy the code
  • Built-in animation list:
UIView.rx.animated.fade(duration: TimeInterval)
UIView.rx.animated.flip(FlipDirection, duration: TimeInterval)
UIView.rx.animated.tick(FlipDirection, duration: TimeInterval)
UIView.rx.animated.animation(duration: TimeInterval, animations: ()->Void)
NSLayoutConstraint.rx.animated.layout(duration: TimeInterval)
Copy the code

2.1.1.2 RxAnimatedCustom animation

You can easily add custom binding animations to match the visual style of your application.

  • Step 1 :(optional) if you are activating a new bind receiver without dynamic bindings (such as uiimageview.rx). Image, UILabel. Rx. Text and more are already included, but you’ll need another attribute)
// This is your class `UILabel`
extension AnimatedSink where Base: UILabel { 
    // This is your property name `text` and value type `String`
    public var text: Binder<String> { 
        let animation = self.type!
        return Binder(self.base) { label, text in
            animation.animate(view: label, block: {
                guard let label = label as? UILabel else { return }
                // Here you update the property
                label.text = text 
            })
        }
    }
}
Copy the code
  • Step 2: Add new animation methods
// This is your class `UIView`
extension AnimatedSink where Base: UIView { 
    // This is your animation name `tick`
    public func tick(_ direction: FlipDirection = .right, duration: TimeInterval) -> AnimatedSink<Base> { 
        // use one of the animation types and provide `setup` and `animation` blocks
        let type = AnimationType<Base>(type: RxAnimationType.spring(damping: 0.33, velocity: 0), duration: duration, setup: { view in
            view.alpha = 0
            view.transform = CGAffineTransform(rotationAngle: direction == .right ?  -0.3 : 0.3)
        }, animations: { view in
            view.alpha = 1
            view.transform = CGAffineTransform.identity
        })
        
        //return AnimatedSink
        return AnimatedSink<Base>(base: self.base, type: type) 
    }
}
Copy the code
  • Step 3: Now you can subscribe using the new animation binding. It is usually bound this wayUIImageView.rx.imageThe following
imageObservable
    .bind(to: imageView.rx.image)
Copy the code

The result is a non-animated binding effect:

If you use your new custom animation binding like this:

imageObservable
    .bind(to: imageView.rx.animated.tick(.right, duration: 0.33).image)
Copy the code

The result looks like this:

If you use the same animation on UILabel:

textObservable
    .bind(to: labelCustom.rx.animated.tick(.left, duration: 0.75).text)
Copy the code

The effect is as follows:

2.1.1.2 RxAnimatedThe installation

  • RxAnimated relies on RxSwift 5+.
  • RxAnimated is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod "RxAnimated"
Copy the code

2.2 Image processing library

2.2.1 Kingfisher

  • KingfisherDownload the source code

    KingfisherSwift is a powerful, pure swift library for downloading and caching images from the web. It gives you an opportunity to use a purely fast way to process remote images in your next application.

2.2.1.1 KingfisherThe characteristics of

  • Asynchronous image download and caching.
  • Based onurlSession of network or locally supplied data loaded images.
  • Provides useful image processors and filters.
  • Multi-tier hybrid cache for memory and disk.
  • Fine control of cache behavior. Customizable expiration date and size limits.
  • Cancelable downloads and automatic reuse of previously downloaded content to improve performance.
  • Separate components. Use the downloader, cache system, and image processor separately as needed.
  • Pre-grab images and display them from the cache to improve your application.
  • UIImageView.NSImageView.NSButtonandUIButtonView extension to directly fromURLSet the image.
  • Built-in transition animation when setting images.
  • Customizable placeholders and indicators for loading images.
  • Easy to expand image processing and image formats.
  • SwiftUISupport.

2.2.1.2 KingfisherSimple to use

2.2.1.2.1 Basic Usage
  • The simplest use case is to use the UIImageView extension to set an image to an image view:
let url = URL(string: "https://example.com/image.png")
imageView.kf.setImage(with: url)
Copy the code

Kingfisher will download the image from the URL, send it to the in-memory cache and disk cache, and display it in imageView. When you use the same URL Settings later, the image is retrieved from the cache and displayed immediately.

You can also write this if you use SwiftUI:

import KingfisherSwiftUI

var body: some View {
    KFImage(URL(string: "https://example.com/image.png")! }Copy the code

In addition, Kingfisher provides advanced usage for solving complex problems, and with these powerful options, you can do difficult tasks with Kingfisher in an easy way. For example, the following code:

let url = URL(string: "https://example.com/high_resolution_image.png")
let processor = DownsamplingImageProcessor(size: imageView.bounds.size)
             >> RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.indicatorType = .activity
imageView.kf.setImage(
    with: url,
    placeholder: UIImage(named: "placeholderImage"),
    options: [
        .processor(processor),
        .scaleFactor(UIScreen.main.scale),
        .transition(.fade(1)),
        .cacheOriginalImage
    ])
{
    result in
    switch result {
    case .success(let value):
        print("Task done for: \(value.source.url? .absoluteString ?? "")")
    case .failure(let error):
        print("Job failed: \(error.localizedDescription)")}}Copy the code

The code above does this:

  1. Download high resolution images.
  2. Samples down to match the size of the image view.
  3. Make it a rounded corner within a given radius.
  4. Display system indicator and placeholder images at download time.
  5. When ready, it animates the small thumbnails with the fade in and fade out effect.
  6. The original large image is also cached to disk for later use to avoid downloading it again in the detail view.
  7. The console log is printed when the task completes, whether it succeeds or fails.
2.2.1.2.2 Clearing the Cache
func clearCache(a) {
        KingfisherManager.shared.cache.clearMemoryCache()
        KingfisherManager.shared.cache.clearDiskCache()
    }
Copy the code
2.2.1.2.3 Downloading images to add UI display
  • Loading pictures shows progress
// Display chrysanthemum
imageView.kf.indicatorType = .activity
 imageView.kf.setImage(with: url, placeholder: nil, options: [.transition(ImageTransition.fade(1))], progressBlock: { (receviveeSize, totalSize) in
            print("\(receviveeSize)/\(totalSize)")
        }) { (image, error, cacheType, imageURL) in
            print("Finished")
            // Load the completed callback
            // image: Image? `nil` means failed
            // error: NSError? non-`nil` means failed
            // cacheType: CacheType
            // .none - Just downloaded
            // .memory - Got from memory cache
            // .disk - Got from disk cache
            // imageUrl: URL of the image
        }
Copy the code
  • Set the chrysanthemum style during download
imageView.kf.indicatorType = .activity
imageView.kf.setImage(with: url)

// Use your own GIF image as a download indicator
let path = Bundle.main.path(forResource: "loader", ofType: "gif")!
let data = try! Data(contentsOf: URL(fileURLWithPath: path)) imageView.kf.indicatorType = .image(imageData: data)
imageView.kf.setImage(with: url)
Copy the code
  • Custom indicator View
struct KYLIndicator: Indicator {
    let view: UIView = UIView(a)func startAnimatingView(a) {
        view.isHidden = false
    }
    func stopAnimatingView(a) {
        view.isHidden = true
    }
    
    init() {
        view.backgroundColor = .red
    }
}

let indicator = KYLIndicator()
imageView.kf.indicatorType = .custom(indicator: indicator)
Copy the code
  • After downloading the image, set the transition effect and fade in effect
imageView.kf.setImage(with: url, options: [.transition(.fade(0.2)))Copy the code
  • Rounded corners are converted to downloaded images before display and caching
let processor = RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])
Copy the code
  • Add an image to Button
        let uiButton: UIButton = UIButton()
        uiButton.kf.setImage(with: url, for: .normal, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)
        uiButton.kf.setBackgroundImage(with: url, for: .normal, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)
Copy the code

2.2.1.3 KingfisherAdvanced Settings

2.2.1.3.1 Setting User-defined Cache Parameters
  • Set the disk cache size (default: 50MB)
// Set the disk cache size
        // Default value is 0, which means no limit.
        // 50 MB
        ImageCache.default.maxDiskCacheSize = 50 * 1024 * 1024
Copy the code
  • Set cache expiration time (default is 3 days)
        // Set the cache expiration time
        // Default value is 60 * 60 * 24 * 7, which means 1 week.
        // 3 days
        ImageCache.default.maxCachePeriodInSecond = 60 * 60 * 24 * 3
Copy the code
  • Set the timeout (default is 15 seconds)
// Default value is 15.
        // 30 second
        ImageDownloader.default.downloadTimeout = 30.0
Copy the code

Other Settings related

// Set the disk cache size
        // Default value is 0, which means no limit.
        // 50 MB
        ImageCache.default.maxDiskCacheSize = 50 * 1024 * 1024
        
        // Get the cache disk usage
        ImageCache.default.calculateDiskCacheSize { size in
            print("Used disk size by bytes: \(size)")}// Set the cache expiration time
        // Default value is 60 * 60 * 24 * 7, which means 1 week.
        // 3 days
        ImageCache.default.maxCachePeriodInSecond = 60 * 60 * 24 * 3
        
        // Set the timeout period
        // Default value is 15.
        // 30 second
        ImageDownloader.default.downloadTimeout = 30.0

    // Clear cache manually
     // Clear memory cache right away.
     cache.clearMemoryCache()
     
     // Clear disk cache. This is an async operation.
     cache.clearDiskCache()
     
     // Clean expired or size exceeded disk cache. This is an async operation.
     cache.cleanExpiredDiskCache()
Copy the code
2.2.1.3.2 Custom Usage
  • Skip cache and force re-download:
imageView.kf.setImage(with: url, options: [.forceRefresh])
Copy the code
  • Use custom key caching instead of urls
let resource = ImageResource(downloadURL: url! , cacheKey:"kyl_cache_key")
 imageView.kf.setImage(with: resource)
Copy the code
  • Cache and download are used separately:

Kingfisher consists of two main parts, ImageDownloader for managing downloads; ImageCache is used to manage the cache, and you can use one of these separately.

// Use ImageDownloader to download images
        ImageDownloader.default.downloadImage(with: url! , options: [], progressBlock:nil) { (image, error, url, data) in
            print("Downloaded Image: \(image)")}// Use ImageCache to cache images
        let image: UIImage = UIImage(named: "xx.png")!
        ImageCache.default.store(image, forKey: "key_for_image")
        
        // Remove a cached image
        // From both memory and disk
        ImageCache.default.removeImage(forKey: "key_for_image")
        
        // Only from memory
        ImageCache.default.removeImage(forKey: "key_for_image",fromDisk: false)
Copy the code
  • Use customDownloaderandcacheInstead of default
        let kyldownloader = ImageDownloader(name: "kongyulu_image_downloader")
        kyldownloader.downloadTimeout = 150.0
        let cache = ImageCache(name: "kyl_longer_cache")
        cache.maxDiskCacheSize = 60 * 60 * 24 * 30
     
        imageView.kf.setImage(with: url, options: [.downloader(kyldownloader), .targetCache(cache)])
        
       // Cancel the download
        imageView.kf.cancelDownloadTask()
Copy the code
  • Use a custom cache path:
            // MARK:- Download images
            imageView.kf.indicatorType = .activity
            let cachePath =  ImageCache.default.cachePath(forKey: PhotoConfig.init().cachePath)
            guard let path = (try? ImageCache.init(name: "cameraPath", cacheDirectoryURL: URL(fileURLWithPath: cachePath))) ?? nil else { return  }
            
            imageView.kf.setImage(with: URL(string: smallUrlStr), placeholder:UIImage(named: "PhotoRectangle") , options: [.targetCache(path)], progressBlock: { (receivedData, totolData) in
                // Use the progress bar or draw the view, and then use percentage% to indicate the progress
                //let percentage = (Float(receivedData)/Float(totolData)) * 100.0
                //print("downloading progress is: \(percentage)%")

                
            }) { result in
                
// switch result {
//                    
// case .success(let imageResult):
// print(imageResult)
//                
// case .failure(let aError):
// print(aError)
/ /}
                
            }
Copy the code
  • Get images to display in advance and add them directly when needed
        let urls = ["http://www.baidu.com/image1.jpg"."http://www.baidu.com/image2.jpg"].map { URL(string: $0)! }
        let prefetcher = ImagePrefetcher(urls: urls) {
            skippedResources, failedResources, completedResources in
            print("These resources are prefetched: \(completedResources)")
        }
        prefetcher.start()
        
        // Later when you need to display these images:
        imageView.kf.setImage(with: urls[0])
        anotherImageView.kf.setImage(with: urls[1])
Copy the code

2.2.1.3 KingfisherHTTPS image download, certificate trust, self-signed certificate trust

  • In development, we may use HTTPS for the server. If the server is using a certificate authority, we can download the image without special processing. However, if the server is using a self-signed certificate instead of a certificate authority, using Kingfisher to download images requires some certificate authentication.

For those of you who are not familiar with the HTTPS handshake process, it is necessary to understand the HTTPS handshake process to understand the certificate authentication mechanism:

An SSL/TLS handshake is performed before sending an HTTPS request. The handshake process is as follows:

  1. The client initiates a handshake request with parameters such as a random number and a list of supported algorithms.
  2. After receiving the request, the server selects an appropriate algorithm and delivers the public key certificate and random number.
  3. The client verifies the server certificate and sends random number information, which is encrypted using the public key.
  4. The server obtains random number information through the private key.
  5. The session ticket generated by both parties is used as the encryption key for subsequent data transmission of the connection.

In Step 3, the client needs to verify the certificate issued by the server. The verification process includes the following two points:

  1. The client uses the locally saved root certificate to unlock the certificate chain and verify that the certificate issued by the server is issued by a trusted authority.
  2. The client needs to check the domain and extension domains of the certificate to see if they contain the host for this request. If both of the above parameters pass, the current server is trusted; otherwise, it is untrusted and the current connection should be broken.

When a client initiates a request using an IP address, the host in the REQUEST URL is replaced by the IP resolved by the HTTP DNS. Therefore, domain mismatch occurs in step 2 of certificate verification, resulting in an SSL/TLS handshake failure.

For more details, please refer to my previous blog post about HTTPS self-signed certificates uploading and downloading files:

IOS Network Protocol (1) Self-signed certificate HTTPS file Upload and download (1)

IOS Audio and Video (45) HTTPS self-signed certificates implement side play

  • HTTPS SSL encryption process for establishing a connection

The diagram below:

Process details:

  1. ① The browser of the client sends a request to the server, and transmits the version number of the SSL protocol of the client, the type of encryption algorithm, the generated random number, and other information needed for communication between the server and the client.
  2. ② The server sends the SSL protocol version number, encryption algorithm type, random number, and other related information to the client. At the same time, the server also sends its certificate to the client.
  3. (3) the client use the server to get the information of the legality of the authentication server, the server includes: the legality of certificate has expired, release the server certificate CA is reliable, the issuer public key certificate can correctly solve the server certificate of “digital signatures” issuers, domain name whether on the server’s certificate and match the actual domain name server. If the validity verification fails, the communication is disconnected. If the validity is verified, the fourth step will be continued.
  4. ④ The client randomly generates a symmetric password for communication, encrypts it with the public key of the server (obtained from the server certificate in Step 2), and sends the encrypted pre-master password to the server.
  5. ⑤ If the server requires the customer’s identity authentication (optional during the handshake), the user can create a random number and then sign the data, and send the random number containing the signature to the server together with the customer’s own certificate and the encrypted “pre-master password”.
  6. ⑥ If the server requires customer identity authentication, the server must verify the validity of the customer certificate and signature random number. The specific validity verification process includes: Check whether the customer’s certificate use date is valid, whether the CA that provides the certificate is reliable, whether the issuing CA’s public key can unlock the digital signature of the issuing CA, and whether the customer’s certificate is in the Certificate Repeal list (CRL). If the inspection does not pass, communication immediately interrupted; If verified, the server unlocks the encrypted “pre-master password” with its own private key, and then performs a series of steps to generate the master communication password (the client generates the same master communication password in the same way).
  7. ⑦ The server and client use the same master password that is “call password”, a symmetric key for SSL protocol encryption and decryption communication of secure data communication. At the same time, the integrity of data communication should be completed during SSL communication to prevent any changes in data communication.
  8. The client sends a message to the server, indicating the following steps of data communication. The master password in ⑦ is a symmetric key, and at the same time notifies the server client that the handshake process is over.
  9. ⑨ The server sends a message to the client indicating that the master password in step 7 is a symmetric key and notifies the client that the server-side handshake process is over.
  10. ⑩ After the SSL handshake is complete, data communication over the SSL secure channel starts. The client and server use the same symmetric key for data communication and check the communication integrity.
  • Kingfisher authentication is actually quite simple, with a few lines of code:
// Fetch the downloader singleton
let downloader = KingfisherManager.shared.downloader

// Trust the Server with IP 106
downloader.trustedHosts = Set(["192.168.1.106"])

// Assign a web image to the ImageView using KingFisher
iconView.kf.setImage(with: iconUrl)

Copy the code

2.2.1.3 KingfisherThe installation

Installation environment requirements: iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ Swift 4.0+

Pod install

pod   'Kingfisher' 
Copy the code

2.2.1.4 KingfisherIntroduction to core Classes

Follow-up…

2.3 Resource file management library

2.3.1 R.swift

  • Source code download:R.swift

2.3.1.1 R.swift Introduction to the

  • R.swift helps us to manage all the icon resources in the project with the same local language. You don’t need to look up the icon name in the resource file every time, and don’t need to look up the key in the multi-language file every time. You can call it as a function, and there is a help prompt.

R. Swift gets strongly typed, autocomplete resources such as images, fonts, and segues in the Swift project.

R.swift gives your code usage resources the following features:

  1. What will the full type, less type conversion and guess method return
  2. Compile-time checks that no more incorrect strings cause your application to crash at run time
  3. Autocomplete, never have to guess the name of the image again

For example, before using R.swift you might write your code like this:

let icon = UIImage(named: "settings-icon")
let font = UIFont(name: "San Francisco", size: 42)
let color = UIColor(named: "indicator highlight")
let viewController = CustomViewController(nibName: "CustomView", bundle: nil)
let string = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.current, "Arthur Dent")

Copy the code

With R.swift, you can write code like this:

let icon = R.image.settingsIcon()
let font = R.font.sanFrancisco(size: 42)
let color = R.color.indicatorHighlight()
let viewController = CustomViewController(nib: R.nib.customView)
let string = R.string.localizable.welcomeWithName("Arthur Dent")
Copy the code

Here are the official Demo: Examples for use in Realm

See how cool the autofill looks:

Autocomplete pictures:

2.3.1.1.1 R.swift Features:

After installing R.swift into your project, you can use r-struct to access resources. If the structure is outdated, just build and R.swift will correct any missing/changed/added resources.

R. Swift currently supports these types of resources:

  • Images

  • Fonts

  • Resource files

  • Colors

  • Localized strings

  • Storyboards

  • Segues

  • Nibs

  • Reusable cells

2.3.1.2 R.swift use

  • Images R.swift will find the Images of the asset directory and image files in your package.

R.swift is not used to access images in this way

let settingsIcon = UIImage(named: "settings-icon")
let gradientBackground = UIImage(named: "gradient.jpg")
Copy the code

After using R.swift, access like this:

let settingsIcon = R.image.settingsIcon()
let gradientBackground = R.image.gradientJpg()
Copy the code

In addition, R.swift supports grouping within folders:

Select Provide namespace to group assets result:

let image = R.image.menu.icons.first()
Copy the code
  • Fonts

Without using r.swift to access:

let lightFontTitle = UIFont(name: "Acme-Light", size: 22)
Copy the code

After using R.swift, access like this:

let lightFontTitle = R.font.acmeLight(size: 22)
Copy the code

Tip: Do system fonts also need this? Take a look at the UIFontComplete library, which has a similar solution for fonts released by Apple for iOS.

  • Resource files

Without using r.swift to access:

let jsonURL = Bundle.main.url(forResource: "seed-data", withExtension: "json")
let jsonPath = Bundle.main.path(forResource: "seed-data", ofType: "json")
Copy the code

After using R.swift, access like this:

let jsonURL = R.file.seedDataJson()
let jsonPath = R.file.seedDataJson.path()
Copy the code
  • Colors

Without using r.swift to access:

view.backgroundColor = UIColor(named: "primary background")
Copy the code

After using R.swift, access like this:

view.backgroundColor = R.color.primaryBackground()
Copy the code
  • Localized strings

Without using r.swift to access:

let welcomeMessage = NSLocalizedString("welcome.message", comment: "")
let settingsTitle = NSLocalizedString("title", tableName: "Settings", comment: "")

// Formatted strings
let welcomeName = String(format: NSLocalizedString("welcome.withName", comment: ""), locale: NSLocale.current, "Alice")

// Stringsdict files
let progress = String(format: NSLocalizedString("copy.progress", comment: ""), locale: NSLocale.current, 4.23)

Copy the code

After using R.swift, access like this:

// Localized strings are grouped per table (.strings file)
let welcomeMessage = R.string.localizable.welcomeMessage()
let settingsTitle = R.string.settings.title()

// Functions with parameters are generated for format strings
let welcomeName = R.string.localizable.welcomeWithName("Alice")

// Functions with named argument labels are generated for stringsdict keys
let progress = R.string.localizable.copyProgress(completed: 4, total: 23)
Copy the code
  • Storyboards

Without using r.swift to access:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialTabBarController = storyboard.instantiateInitialViewController() as? UITabBarController
let settingsController = storyboard.instantiateViewController(withIdentifier: "settingsController") as? SettingsController

Copy the code

After using R.swift, access like this:

let storyboard = R.storyboard.main()
let initialTabBarController = R.storyboard.main.initialViewController()
let settingsController = R.storyboard.main.settingsController()
Copy the code
  • Segues

Without using r.swift to access:

// Trigger segue with:
performSegue(withIdentifier: "openSettings", sender: self)

// And then prepare it:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let settingsController = segue.destination as? SettingsController.let segue = segue as? CustomSettingsSegue, segue.identifier == "openSettings" {
      segue.animationType = .LockAnimation
      settingsController.lockSettings = true}}Copy the code

After using R.swift, access like this:

// Trigger segue with:
performSegue(withIdentifier: R.segue.overviewController.openSettings, sender: self)

// And then prepare it:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  if let typedInfo = R.segue.overviewController.openSettings(segue: segue) {
    typedInfo.segue.animationType = .LockAnimation
    typedInfo.destinationViewController.lockSettings = true}}Copy the code

Tip: Take a look at the SegueManager library, which makes the Segues block based and compatible with R.FT.

  • Nibs

Without using r.swift to access:

let nameOfNib = "CustomView"
let customViewNib = UINib(nibName: "CustomView", bundle: nil)
let rootViews = customViewNib.instantiate(withOwner: nil, options: nil)
let customView = rootViews[0] as? CustomView

let viewControllerWithNib = CustomViewController(nibName: "CustomView", bundle: nil)
Copy the code

After using R.swift, access like this:

let nameOfNib = R.nib.customView.name
let customViewNib = R.nib.customView()
let rootViews = R.nib.customView.instantiate(withOwner: nil)
let customView = R.nib.customView.firstView(owner: nil)

let viewControllerWithNib = CustomViewController(nib: R.nib.customView)
Copy the code
  • Reusable cells

(1) reuse TableViewCell

Without using r.swift to access:

class FaqAnswerController: UITableViewController {
  override func viewDidLoad(a) {
    super.viewDidLoad()
    let textCellNib = UINib(nibName: "TextCell", bundle: nil)
    tableView.register(textCellNib, forCellReuseIdentifier: "TextCellIdentifier")}override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let textCell = tableView.dequeueReusableCell(withIdentifier: "TextCellIdentifier".for: indexPath) as! TextCell
    textCell.mainLabel.text = "Hello World"
    return textCell
  }
}
Copy the code

After using R.swift, access like this:

On the Reusable Cell Interface Generator Properties check panel, set the cell Identifier field to the same value that you want to register and dequeue.

class FaqAnswerController: UITableViewController {
  override func viewDidLoad(a) {
    super.viewDidLoad()
    tableView.register(R.nib.textCell)
  }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let textCell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.textCell, for: indexPath)!
    textCell.mainLabel.text = "Hello World"
    return textCell
  }
}
Copy the code

(2) reuse CollectionViewCell

Without using r.swift to access:

class RecentsController: UICollectionViewController {
  override func viewDidLoad(a) {
    super.viewDidLoad()
    let talkCellNib = UINib(nibName: "TalkCell", bundle: nil) collectionView? .register(talkCellNib, forCellWithReuseIdentifier:"TalkCellIdentifier")}override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TalkCellIdentifier".for: indexPath) as! TalkCell
    cell.configureCell("Item \(indexPath.item)")
    return cell
  }
}
Copy the code

After using R.swift, access like this:

On the Reusable Cell Interface Generator Properties check panel, set the cell Identifier field to the same value that you want to register and dequeue.

class RecentsController: UICollectionViewController {
  override func viewDidLoad(a) {
    super.viewDidLoad() collectionView? .register(R.nib.talkCell)
  }

  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.talkCell, for: indexPath)!
    cell.configureCell("Item \(indexPath.item)")
    return cell
  }
}
Copy the code

2.3.1.2 R.swift The installation

CocoaPods is the recommended installation because it avoids including any binaries in your project.

Note :R.swift is a tool for building steps; it is not a dynamic library. Therefore, it is not possible to install Carthage.

Install CocoaPods(recommended).

  1. addpod 'R.swift'Go to your Podfile and runpod install
  2. In Xcode: Click the project in the file list, select the target under Target, click the Build Phase TAB, and add a new run script phase by clicking the small plus icon in the upper left corner
  3. Drag the new run script stage above the compile source stage and under the Check POD listing. Lock, expand and paste the following script:"$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/R.generated.swift"
  4. will$TEMP_DIR/rswift-lastrunAdd to input File, will$SRCROOT/R.generated.swiftAdd to the Output file in the build phase
  5. Set up your project and you’ll see one in FinderR.generated.swiftin$SRCROOTIn the folder, dragR.generated.swiftFile to your project, uncheck Copy if necessary

2.3.2 SwiftLint

  • SwiftLint

2.4 Key Management library

Against 2.4.1KeychainAccess

  • KeychainAccess

2.5 Automatic layout library

2.5.1 SnapKit

  • Source: SnapKit

2.6 UI libraries

2.6.1 NVActivityIndicatorView

  • Source: NVActivityIndicatorView

2.6.2 ImageSlidershow/Kingfisher

  • The source code download: ImageSlidershow/Kingfisher

2.6.3 DZNEmptyDataSet

  • DZNEmptyDataSet

2.6.4 Hero

  • Source code download: Hero

2.6.5 Localize-Swift

  • Source code: Localize-Swift

2.6.6 RAMAnimatedTabBarController

  • The source code download: RAMAnimatedTabBarController

2.6.7 AcknowList

  • Source: AcknowList

2.6.8 KafkaRefresh

  • Source: KafkaRefresh

2.6.9 WhatsNewKit

  • Download the source: WhatsNewKit

2.6.10 Highlightr

  • Highlightr

2.6.11 DropDown

  • DropDown

2.6.12 Toast-Swift

  • Download the source code: toasts-Swift

2.6.13 HMSegmentedControl

  • HMSegmentedControl

2.6.14 FloatingPanel

  • Source code: FloatingPanel

2.6.15 MessageKit

  • MessageKit

2.6.16 MultiProgressView

  • MultiProgressView

2.6.17 IQKeyboardManagerSwift

  • IQKeyboardManagerSwift

2.7 Log Management library

2.7.1 CocoaLumberjack/Swift

  • Download source code: CocoaLumberjack/Swift

2.8 Buried data base

2.8.1 Umbrella

  • Source code: Umbrella

2.8.2 Umbrella/Mixpanel

2.8.3 Umbrella/Firebase

2.8.4 Mixpanel

  • Source code download: Mixpanel

2.8.5 Firebace/Analytics

2.9 Advertising tool point library

2.9.1 Firebase/AdMob

2.9.2 Google-Mobile-Ads-SDK

2.10 Performance optimization related libraries

2.10.1 Fabric

2.10.2 Crashlytics

2.11 Other Tool Libraries

2.11.1 FLEX

  • Source code download: FLEX

2.11.2 SwifterSwift

  • Source code download: SwifterSwift

2.11.3 BonMot

  • Source code download: BonMot

2.11.4 DateToolsSwift

  • Download the source: DateToolsSwift

2.11.5 SwiftDate

  • SwiftDate SwiftDate

3. Architecture analysis of SwiftHub project