開源項目分析(SwiftHub)Rxswift + MVVM + Moya 架構分析(二)第三方框架使用(中)

開源項目分析(SwiftHub)Rxswift + MVVM + Moya 架構分析(一)第三方框架使用 (上)git

開源項目分析(SwiftHub)Rxswift + MVVM + Moya 架構分析(二)第三方框架使用 (中)github

@[TOC]算法

2. SwiftHub使用的第三方庫

這篇博客是上篇博客「開源項目分析(SwiftHub)Rxswift + MVVM + Moya 架構分析(一)第三方框架使用」 的續集,因爲篇幅過程,拆成幾部分了。spring

先回顧一下第三方框架圖:json

SwiftHub項目用的第三方庫

2.1 Rxswift 家族庫

2.1.1 RxAnimated

RxAnimated的星星
RxAnimated 爲RxCocoa的綁定提供了動畫接口

它提供了一些預約義的動畫綁定,並提供了一種靈活的機制,讓您能夠添加本身的預約義動畫,並在與RxCocoa綁定時使用它們。swift

2.1.1.1 RxAnimated基本動畫使用

當與RxCocoa綁定值時,你能夠這樣寫:數組

textObservable
  .bind(to: labelFlip.rx.text)
複製代碼

label更新動畫

每當observable發出一個新的字符串值時,它都會更新標籤的文本。但這是忽然發生的,沒有任何過渡。使用RxAnimated,你可使用animated擴展來綁定值和動畫,就像這樣:瀏覽器

textObservable
  .bind(animated: labelFlip.rx.animated.flip(.top, duration: 0.33).text)
複製代碼

labelFlip動畫

「不一樣之處在於」您使用bind(animated:)而不是bind(to:),而後您插入animated.flip(.top, duration: 0.33)(或其餘提供或自定義動畫方法之一)之間的rx和屬性接收器你想使用。緩存

2.1.1.2 RxAnimated基本動畫列表

  • 內置動畫類型列表:
UIView.rx.animated...isHidden
UIView.rx.animated...alpha
UILabel.rx.animated...text
UILabel.rx.animated...attributedText
UIControl.rx.animated...isEnabled
UIControl.rx.animated...isSelected
UIButton.rx.animated...title
UIButton.rx.animated...image
UIButton.rx.animated...backgroundImage
UIImageView.rx.animated...image
NSLayoutConstraint.rx.animated...constant
NSLayoutConstraint.rx.animated...isActive
複製代碼
  • 內置動畫列表:
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)
複製代碼

2.1.1.2 RxAnimated自定義動畫

您能夠輕鬆地添加自定義綁定動畫來匹配應用程序的視覺風格。安全

  • 第一步:(可選)若是你正在激活一個沒有動態綁定的新綁定接收器(例如UIImageView.rx)。形象,UILabel.rx。文本和更多的已經包括在內,但你須要另外一個屬性)
// 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 
            })
        }
    }
}
複製代碼
  • 第二步:添加新的動畫方法
// 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) 
    }
}
複製代碼
  • 第三步:如今可使用新的動畫綁定訂閱了。一般是這樣綁定UIImageView.rx.image 以下
imageObservable
    .bind(to: imageView.rx.image)
複製代碼

結果是非動畫綁定的效果:

普通點擊動畫

若是你使用你的新自定義動畫綁定像這樣:

imageObservable
    .bind(to: imageView.rx.animated.tick(.right, duration: 0.33).image)
複製代碼

修改後的效果是這樣的:

修改後的效果

若是你在UILabel上使用相同的動畫:

textObservable
    .bind(to: labelCustom.rx.animated.tick(.left, duration: 0.75).text)
複製代碼

效果以下:

Label使用自定義動畫效果

2.1.1.2 RxAnimated 安裝

  • RxAnimated依賴於RxSwift 5+。
  • RxAnimated能夠經過CocoaPods得到。要安裝它,只需添加如下行到您的Podfile:
pod "RxAnimated"
複製代碼

2.2 圖像處理庫

2.2.1 Kingfisher

  • Kingfisher源碼下載
    Kingfisher的星星
    Kingfisher是一個強大的,純粹的swift庫下載和緩存圖像從網上。它爲你提供了一個機會,使用一個純粹的快速的方式來處理你的下一個應用程序中的遠程圖像。

2.2.1.1 Kingfisher特色

  • 異步圖像下載和緩存。
  • 從基於url會話的網絡或本地提供的數據加載圖像。
  • 提供了有用的圖像處理器和過濾器。
  • 用於內存和磁盤的多層混合緩存。
  • 對緩存行爲的精細控制。可自定義的過時日期和大小限制。
  • 可取消的下載和自動重用之前下載的內容,以提升性能。
  • 獨立的組件。根據須要分別使用下載器、緩存系統和圖像處理器。
  • 預抓取圖片並從緩存中顯示,以提高你的應用程序。
  • UIImageView, NSImageView, NSButtonUIButton的視圖擴展來直接從URL設置圖像。
  • 內置過渡動畫時,設置圖像。
  • 加載圖像時可自定義的佔位符和指示器。
  • 易於擴展的圖像處理和圖像格式。
  • SwiftUI支持。

2.2.1.2 Kingfisher簡單使用

2.2.1.2.1 基本用法
  • 最簡單的用例是使用UIImageView擴展將圖像設置爲圖像視圖:
let url = URL(string: "https://example.com/image.png")
imageView.kf.setImage(with: url)
複製代碼

Kingfisher將從url下載圖像,將其發送到內存緩存和磁盤緩存,並在imageView中顯示。當您稍後使用相同的URL設置時,圖像將從緩存中檢索並當即顯示。

若是你使用SwiftUI也能夠這樣寫:

import KingfisherSwiftUI

var body: some View {
    KFImage(URL(string: "https://example.com/image.png")!)
}
複製代碼

此外,Kingfisher還提供了一些高階用法,用於解決複雜的問題,有了這些強大的選項,您能夠用簡單的方式用Kingfisher完成困難的任務。 例如,下面的代碼:

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)")
    }
}
複製代碼

上面代碼作了這些操做:

  1. 下載高分辨率圖像。
  2. 向下採樣以匹配圖像視圖的大小。
  3. 使它在給定的半徑內成爲一個圓角。
  4. 下載時顯示系統指示符和佔位符圖像。
  5. 準備好後,它會用「漸入淡出」效果使小的縮略圖產生動畫效果。
  6. 原始的大圖也被緩存到磁盤供之後使用,以免在詳細視圖中再次下載它。
  7. 當任務完成時,不管是成功仍是失敗,都會打印控制檯日誌。
2.2.1.2.2 清除緩存
func clearCache() {
        KingfisherManager.shared.cache.clearMemoryCache()
        KingfisherManager.shared.cache.clearDiskCache()
    }
複製代碼
2.2.1.2.3 下載圖片增長UI顯示
  • 加載圖片顯示進度
//顯示菊花
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")
            // 加載完成的回調
            // 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
        }
複製代碼
  • 下載過程當中 設置菊花樣式
imageView.kf.indicatorType = .activity
imageView.kf.setImage(with: url)

//使用本身的gif圖片做爲下載指示器
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)
複製代碼
  • 訂製指示器view
struct KYLIndicator: Indicator {
    let view: UIView = UIView()
    
    func startAnimatingView() {
        view.isHidden = false
    }
    func stopAnimatingView() {
        view.isHidden = true
    }
    
    init() {
        view.backgroundColor = .red
    }
}

let indicator = KYLIndicator()
imageView.kf.indicatorType = .custom(indicator: indicator)
複製代碼
  • 圖片下載完成後,設置過分效果,淡入效果
imageView.kf.setImage(with: url, options: [.transition(.fade(0.2))])
複製代碼
  • 在顯示和緩存以前將下載的圖像轉換成圓角
let processor = RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])
複製代碼
  • 對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)
複製代碼

2.2.1.3 Kingfisher高級設置

2.2.1.3.1 設置自定義緩存參數
  • 設置磁盤緩存大小(默認是50MB)
// 設置磁盤緩存大小
        // Default value is 0, which means no limit.
        // 50 MB
        ImageCache.default.maxDiskCacheSize = 50 * 1024 * 1024
複製代碼
  • 設置緩存過時時間(默認是3天)
// 設置緩存過時時間
        // Default value is 60 * 60 * 24 * 7, which means 1 week.
        // 3 days
        ImageCache.default.maxCachePeriodInSecond = 60 * 60 * 24 * 3
複製代碼
  • 設置超時時間(默認是15秒)
// Default value is 15.
        // 30 second
        ImageDownloader.default.downloadTimeout = 30.0
複製代碼

其餘設置相關

// 設置磁盤緩存大小
        // Default value is 0, which means no limit.
        // 50 MB
        ImageCache.default.maxDiskCacheSize = 50 * 1024 * 1024
        
        // 獲取緩存磁盤使用大小
        ImageCache.default.calculateDiskCacheSize { size in
            print("Used disk size by bytes: \(size)")
        }
        
        // 設置緩存過時時間
        // Default value is 60 * 60 * 24 * 7, which means 1 week.
        // 3 days
        ImageCache.default.maxCachePeriodInSecond = 60 * 60 * 24 * 3
        
        // 設置超時時間
        // 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()
複製代碼
2.2.1.3.2 自定義用法
  • 跳過緩存,強制從新下載:
imageView.kf.setImage(with: url, options: [.forceRefresh])
複製代碼
  • 使用自定義key緩存,而不是用url
let resource = ImageResource(downloadURL: url!, cacheKey: "kyl_cache_key")
 imageView.kf.setImage(with: resource)
複製代碼
  • 緩存和下載分開使用:

Kingfisher 主要由兩部分組成,ImageDownloader用於管理下載;ImageCache用於管理緩存,你能夠單獨使用其中一個.

//使用ImageDownloader下載圖片
        ImageDownloader.default.downloadImage(with: url!, options: [], progressBlock: nil) { (image, error, url, data) in
            print("Downloaded Image: \(image)")
        }
        
       // 使用ImageCache緩存圖片
        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)
複製代碼
  • 使用自定義的Downloadercache代替默認的
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)])
        
       // 取消下載
        imageView.kf.cancelDownloadTask()
複製代碼
  • 使用自定義的緩存路徑:
// MARK:- 下載圖片
            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
                // 這裏用進度條或者繪製view均可以,而後根據 percentage% 表示進度就好了
                //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)
// }
                
            }
複製代碼
  • 預先獲取要顯示的圖片,須要顯示時在直接添加
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])
複製代碼

2.2.1.3 Kingfisher HTTPS 圖片下載,證書信任,自簽名證書信任

  • 開發中,咱們可能服務器用的是HTTPS的方式,這個時候若是服務器端是使用的證書頒發機構的證書,咱們下載圖片不須要特殊處理,就能夠下載到圖片。可是,若是服務器使用的不是認證機構認證的證書,而是使用自簽名證書,使用Kingfisher 下載圖片須要作一下證書認證處理。

可能有些朋友不太熟悉HTTPS握手的過程,要理解證書認證機制,有必要理解一下HTTPS握手過程:

發送HTTPS請求首先要進行SSL/TLS握手,握手過程大體以下:

  1. 客戶端發起握手請求,攜帶隨機數、支持算法列表等參數。
  2. 服務端收到請求,選擇合適的算法,下發公鑰證書和隨機數。
  3. 客戶端對服務端證書進行校驗,併發送隨機數信息,該信息使用公鑰加密。
  4. 服務端經過私鑰獲取隨機數信息。
  5. 雙方根據以上交互的信息生成session ticket,用做該鏈接後續數據傳輸的加密密鑰。

第3步中,客戶端須要驗證服務端下發的證書,驗證過程有如下兩個要點:

  1. 客戶端用本地保存的根證書解開證書鏈,確認服務端下發的證書是由可信任的機構頒發的。
  2. 客戶端須要檢查證書的domain域和擴展域,看是否包含本次請求的host。 若是上述兩點都校驗經過,就證實當前的服務端是可信任的,不然就是不可信任,應當中斷當前鏈接。

當客戶端直接使用IP地址發起請求時,請求URL中的host會被替換成HTTP DNS解析出來的IP,因此在證書驗證的第2步,會出現domain不匹配的狀況,致使SSL/TLS握手不成功。

更多詳情請參考我以前寫的一篇關於HTTPS自簽名證書上傳下載文件的博客:

IOS 網絡協議(一) 自簽名證書HTTPS文件上傳下載(上)

IOS音視頻(四十五)HTTPS 自簽名證書 實現邊下邊播

  • HTTPS SSL加密創建鏈接過程

以下圖:

HTTPS SSL加密創建鏈接過程
過程詳解:

  1. ①客戶端的瀏覽器向服務器發送請求,並傳送客戶端SSL 協議的版本號,加密算法的種類,產生的隨機數,以及其餘服務器和客戶端之間通信所須要的各類信息。
  2. ②服務器向客戶端傳送SSL 協議的版本號,加密算法的種類,隨機數以及其餘相關信息,同時服務器還將向客戶端傳送本身的證書。
  3. ③客戶端利用服務器傳過來的信息驗證服務器的合法性,服務器的合法性包括:證書是否過時,發行服務器證書的CA 是否可靠,發行者證書的公鑰可否正確解開服務器證書的「發行者的數字簽名」,服務器證書上的域名是否和服務器的實際域名相匹配。若是合法性驗證沒有經過,通信將斷開;若是合法性驗證經過,將繼續進行第四步。
  4. ④用戶端隨機產生一個用於通信的「對稱密碼」,而後用服務器的公鑰(服務器的公鑰從步驟②中的服務器的證書中得到)對其加密,而後將加密後的「預主密碼」傳給服務器。
  5. ⑤若是服務器要求客戶的身份認證(在握手過程當中爲可選),用戶能夠創建一個隨機數而後對其進行數據簽名,將這個含有簽名的隨機數和客戶本身的證書以及加密過的「預主密碼」一塊兒傳給服務器。
  6. ⑥若是服務器要求客戶的身份認證,服務器必須檢驗客戶證書和簽名隨機數的合法性,具體的合法性驗證過程包括:客戶的證書使用日期是否有效,爲客戶提供證書的CA 是否可靠,發行CA 的公鑰可否正確解開客戶證書的發行CA 的數字簽名,檢查客戶的證書是否在證書廢止列表(CRL)中。檢驗若是沒有經過,通信馬上中斷;若是驗證經過,服務器將用本身的私鑰解開加密的「預主密碼」,而後執行一系列步驟來產生主通信密碼(客戶端也將經過一樣的方法產生相同的主通信密碼)。
  7. ⑦服務器和客戶端用相同的主密碼即「通話密碼」,一個對稱密鑰用於SSL 協議的安全數據通信的加解密通信。同時在SSL 通信過程當中還要完成數據通信的完整性,防止數據通信中的任何變化。
  8. ⑧客戶端向服務器端發出信息,指明後面的數據通信將使用的步驟. ⑦中的主密碼爲對稱密鑰,同時通知服務器客戶端的握手過程結束。
  9. ⑨服務器向客戶端發出信息,指明後面的數據通信將使用的步驟⑦中的主密碼爲對稱密鑰,同時通知客戶端服務器端的握手過程結束。
  10. ⑩SSL 的握手部分結束,SSL 安全通道的數據通信開始,客戶和服務器開始使用相同的對稱密鑰進行數據通信,同時進行通信完整性的檢驗。
  • Kingfisher 的認證其實很簡單,幾行代碼就能夠了:
//取出downloader單例
let downloader = KingfisherManager.shared.downloader

//信任ip爲106的Server,這裏傳入的是一個數組,能夠信任多個IP
downloader.trustedHosts = Set(["192.168.1.106"])

//使用KingFisher給ImageView賦網絡圖片
iconView.kf.setImage(with: iconUrl)

複製代碼

2.2.1.3 Kingfisher安裝

安裝環境要求: iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ Swift 4.0+

Pod install

pod   'Kingfisher' 
複製代碼

2.2.1.4 Kingfisher核心類介紹

Kingfisher架構圖

後續補充...

2.3 資源文件管理庫

2.3.1 R.swift

2.3.1.1 R.swift 簡介

  • R.swift 能幫助咱們把項目裏面的全部圖標資源和本地化語言統一管理,你不在須要每次從資源文件裏面去查找圖標的名稱,也不要去多語言文件裏面去查找key了,直接能用函數的方式調用,並且還能有幫助提示。

R.swift 在Swift項目中得到強類型、自動完成的資源,如圖像、字體和segue。

R.swift 使你的代碼使用資源具備以下特性:

  1. 全類型,較少類型轉換和猜想方法將返回什麼
  2. 編譯時檢查,沒有更多的不正確的字符串,使您的應用程序崩潰在運行時
  3. 自動完成,永遠沒必要再猜圖像的名字

例如,使用R.swift 以前你可能會這樣寫你的代碼:

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")

複製代碼

使用R.swift 以後,你能夠這樣寫代碼:

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")
複製代碼

這裏有官方提供的Demo:Examples , 在realm中使用

看看自動填充的效果多酷:

自動完成圖片:

自動完成圖片:
編譯時檢查圖片:

在這裏插入圖片描述

2.3.1.1.1 R.swift 特色:

安裝R.swift 到您的項目後,您可使用R-struct訪問資源。若是結構是過期的,只是創建和R.swift 將糾正任何失蹤/改變/增長的資源。

R.swift 目前支持這些類型的資源:

2.3.1.2 R.swift 使用

  • Images R.swift 將在你的包中找到資產目錄和圖像文件的圖像。

沒有使用R.swift 這樣訪問圖片

let settingsIcon = UIImage(named: "settings-icon")
let gradientBackground = UIImage(named: "gradient.jpg")
複製代碼

使用R.swift 後這樣訪問:

let settingsIcon = R.image.settingsIcon()
let gradientBackground = R.image.gradientJpg()
複製代碼

此外R.swift 還支持文件夾中分組的方式:

選擇「提供名稱空間」分組資產結果:

選這圖片
而後這樣使用:

let image = R.image.menu.icons.first()
複製代碼

沒有使用R.swift 這樣訪問:

let lightFontTitle = UIFont(name: "Acme-Light", size: 22)
複製代碼

使用R.swift 後這樣訪問:

let lightFontTitle = R.font.acmeLight(size: 22)
複製代碼

提示:系統字體也須要這個嗎? 看一下UIFontComplete庫,它有一個相似的解決方案,用於蘋果公司發佈的iOS字體。

沒有使用R.swift 這樣訪問:

let jsonURL = Bundle.main.url(forResource: "seed-data", withExtension: "json")
let jsonPath = Bundle.main.path(forResource: "seed-data", ofType: "json")
複製代碼

使用R.swift 後這樣訪問:

let jsonURL = R.file.seedDataJson()
let jsonPath = R.file.seedDataJson.path()
複製代碼

沒有使用R.swift 這樣訪問:

view.backgroundColor = UIColor(named: "primary background")
複製代碼

使用R.swift 後這樣訪問:

view.backgroundColor = R.color.primaryBackground()
複製代碼

沒有使用R.swift 這樣訪問:

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)

複製代碼

使用R.swift 後這樣訪問:

// 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)
複製代碼

沒有使用R.swift 這樣訪問:

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

複製代碼

使用R.swift 後這樣訪問:

let storyboard = R.storyboard.main()
let initialTabBarController = R.storyboard.main.initialViewController()
let settingsController = R.storyboard.main.settingsController()
複製代碼

沒有使用R.swift 這樣訪問:

// 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
    }
  }
複製代碼

使用R.swift 後這樣訪問:

// 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
  }
}

複製代碼

提示:看看SegueManager庫,它使segues塊爲基礎,並與r.s ft兼容。

沒有使用R.swift 這樣訪問:

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)
複製代碼

使用R.swift 後這樣訪問:

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)
複製代碼

(1) 重用TableViewCell

沒有使用R.swift 這樣訪問:

class FaqAnswerController: UITableViewController {
  override func viewDidLoad() {
    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
  }
}
複製代碼

使用R.swift 後這樣訪問:

在可重用單元格界面生成器「屬性」檢查面板上,將單元格「標識符」字段設置爲要註冊和退出隊列的相同值。

class FaqAnswerController: UITableViewController {
  override func viewDidLoad() {
    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
  }
}
複製代碼

(2) 重用CollectionViewCell

沒有使用R.swift 這樣訪問:

class RecentsController: UICollectionViewController {
  override func viewDidLoad() {
    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
  }
}
複製代碼

使用R.swift 後這樣訪問:

在可重用單元格界面生成器「屬性」檢查面板上,將單元格「標識符」字段設置爲要註冊和退出隊列的相同值。

class RecentsController: UICollectionViewController {
  override func viewDidLoad() {
    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
  }
}
複製代碼

2.3.1.2 R.swift 安裝

CocoaPods是推薦的安裝方式,由於這樣能夠避免在項目中包含任何二進制文件。

注意:R.swift 是一個用於構建步驟的工具,它不是一個動態庫。所以,它不可能安裝Carthage。

CocoaPods(推薦) 安裝步驟:

  1. 添加pod 'R.swift'到您的Podfile和運行pod install
  2. 在Xcode中:單擊文件列表中的項目,在「目標」下選擇目標,單擊「構建階段」選項卡,經過單擊左上角的小加號圖標添加新的運行腳本階段
  3. 將新的運行腳本階段拖動到編譯源階段之上,並在檢查pod清單之下。鎖定,展開並粘貼如下腳本:"$PODS_ROOT/R.swift/rswift" generate "$SRCROOT/R.generated.swift"
  4. $TEMP_DIR/rswift-lastrun添加到「輸入文件」中,將$SRCROOT/R.generated.swift添加到構建階段的「輸出文件」中
  5. 創建你的項目,在Finder中你會看到一個R.generated.swift$SRCROOT文件夾中,拖動R.generated.swift文件到你的項目中,若是須要,取消勾選Copy項

2.3.2 SwiftLint

2.4 祕鑰管理庫

2.4.1 KeychainAccess

2.5 自動佈局庫

2.5.1 SnapKit

2.6 UI相關庫

2.6.1 NVActivityIndicatorView

2.6.2 ImageSlidershow/Kingfisher

2.6.3 DZNEmptyDataSet

2.6.4 Hero

  • 源碼下載:Hero

2.6.5 Localize-Swift

2.6.6 RAMAnimatedTabBarController

2.6.7 AcknowList

2.6.8 KafkaRefresh

2.6.9 WhatsNewKit

2.6.10 Highlightr

2.6.11 DropDown

2.6.12 Toast-Swift

2.6.13 HMSegmentedControl

2.6.14 FloatingPanel

2.6.15 MessageKit

2.6.16 MultiProgressView

2.6.17 IQKeyboardManagerSwift

2.7 日誌管理庫

2.7.1 CocoaLumberjack/Swift

2.8 數據埋點庫

2.8.1 Umbrella

2.8.2 Umbrella/Mixpanel

2.8.3 Umbrella/Firebase

2.8.4 Mixpanel

2.8.5 Firebace/Analytics

2.9 廣告工具點庫

2.9.1 Firebase/AdMob

2.9.2 Google-Mobile-Ads-SDK

2.10 性能優化相關庫

2.10.1 Fabric

2.10.2 Crashlytics

2.11 其餘工具類庫

2.11.1 FLEX

  • 源碼下載: FLEX

2.11.2 SwifterSwift

2.11.3 BonMot

2.11.4 DateToolsSwift

2.11.5 SwiftDate

3. SwiftHub項目採用的架構分析

相關文章
相關標籤/搜索