自己在Swift項目中使用或者看到的好用的框架

今年年初跳槽炸客,順便也從 OC 轉為了 Swift 适贸,所以之前 OC 版的框架就暫時不更新了,重新寫了這篇文章察署,是我在 Swift 開發(fā)過程中用到闷游、或者看到,個人覺得比較好用的框架,有新的偶遇脐往,也會更新的休吠,有興趣的可以去瞄一眼

內置調試工具

  • CocoaDebug
    iOS APP 內置調試工具,支持log日志查看业簿、網絡抓包瘤礁、沙盒查看等功能,代碼零入侵梅尤。
    Appdelegate類里面設置:
private func customCocoaDebug() {
    //--- If want to custom CocoaDebug settings ---
//        CocoaDebug.serverURL = "google.com"
//        CocoaDebug.ignoredURLs = ["aaa.com", "bbb.com"]
//        CocoaDebug.onlyURLs = ["ccc.com", "ddd.com"]
//        CocoaDebug.ignoredPrefixLogs = ["aaa", "bbb"]
//        CocoaDebug.onlyPrefixLogs = ["ccc", "ddd"]
//        CocoaDebug.emailToRecipients = ["aaa@gmail.com", "bbb@gmail.com"]
//        CocoaDebug.emailCcRecipients = ["ccc@gmail.com", "ddd@gmail.com"]
    CocoaDebug.mainColor = "#fd9727"
//        CocoaDebug.additionalViewController = TestController.init()
    
    //Deprecated! If want to support protobuf, check branch: origin/protobuf_support
    //--- If use Google's Protocol buffers ---
//        CocoaDebug.protobufTransferMap = [
//            "your_api_keywords_1": ["your_protobuf_className_1"],
//            "your_api_keywords_2": ["your_protobuf_className_2"],
//            "your_api_keywords_3": ["your_protobuf_className_3"]
//        ]
    
    //--- If want to manual enable App logs (Take effect the next time when app starts) ---
    CocoaDebugSettings.shared.enableLogMonitoring = true
}

記得在didFinishLaunchingWithOptions 內調用

重寫一下打印方法柜思,這個不要寫在Appdelegate類里面,平級寫

//MARK: - override Swift `print` method
public func MYLog<T>(file: String = #file, function: String = #function, line: Int = #line, _ message: T, color: UIColor = .white) {
#if DEBUG
    Swift.print(message)
    _SwiftLogHelper.shared.handleLog(file: file, function: function, line: line, message: message, color: color)
#endif
}

而在需要觀察打印log的地方這樣寫:

MYLog("測試cocoaDebug有沒有用", color: .red)
  • LifetimeTracker
    檢測循環(huán)引用巷燥、內存泄漏

  • FLEX
    Star很高的在線調試工具赡盘,主要是可以不用連著Xcode實時看數(shù)據(jù)庫的數(shù)據(jù),Log 的話有一堆不需要的缰揪,但是很多需要的卻沒有陨享,暫時我還不知道怎么用這個框架的 Log。cash 我寫了一個數(shù)組越界钝腺,但是并不知道在哪里可以看抛姑。以下是集成:

pod 'FLEX', :configurations => ['Debug']
FLEXManager.shared.showExplorer()
  • CocoaDebug
    也是一個在線看log、crash艳狐、文件定硝、網絡請求等的框架,但是我寫了很多 Log僵驰,他幾乎只會顯示他自己的 CocoaDebugTool.log(with: "446633")喷斋,crash 我寫了一個數(shù)組越界唁毒,但是并沒有抓到蒜茴。以下是集成方法:
pod 'CocoaDebug', :configurations => ['Debug']
extension AppDelegate {
    
    private func customCocoaDebug() {
        //--- If want to custom CocoaDebug settings ---
//        CocoaDebug.serverURL = "google.com"
//        CocoaDebug.ignoredURLs = ["aaa.com", "bbb.com"]
//        CocoaDebug.onlyURLs = ["ccc.com", "ddd.com"]
//        CocoaDebug.ignoredPrefixLogs = ["aaa", "bbb"]
//        CocoaDebug.onlyPrefixLogs = ["ccc", "ddd"]
//        CocoaDebug.emailToRecipients = ["aaa@gmail.com", "bbb@gmail.com"]
//        CocoaDebug.emailCcRecipients = ["ccc@gmail.com", "ddd@gmail.com"]
        CocoaDebug.mainColor = "#fd9727"
//        CocoaDebug.additionalViewController = TestController.init()
        
        //Deprecated! If want to support protobuf, check branch: origin/protobuf_support
        //--- If use Google's Protocol buffers ---
//        CocoaDebug.protobufTransferMap = [
//            "your_api_keywords_1": ["your_protobuf_className_1"],
//            "your_api_keywords_2": ["your_protobuf_className_2"],
//            "your_api_keywords_3": ["your_protobuf_className_3"]
//        ]
        
        //--- If want to manual enable App logs (Take effect the next time when app starts) ---
        CocoaDebugSettings.shared.enableLogMonitoring = true
    }
    
}
  • LLDebugTool
    這個跟上面兩個類似,都是可以看 Crash浆西、Log粉私、網絡請求、文件等近零,比較特別的就是
    :手機的CPU等使用情況诺核、虛擬定位。這個框架的 crash 確實是可以看到的久信,但是同時窖杀,他的 Log 也是只能看到自己的 LLog.log(message: "123456789")。以下是集成:
pod 'LLDebugToolSwift' , :configurations => ['Debug']
extension AppDelegate {
    
    func setupLLDebug() {
        LLDebugTool.shared().startWorking{ config in
            config.logStyle = .detail
        }
    }
    
}
  • LifetimeTracker
    檢查項目的內存泄漏問題裙士,但是我沒弄懂怎么使用入客。以下為集成方法:
pod 'LifetimeTracker'
  • LifetimeTracker
    騰訊也出品了一個檢測內存泄漏的。

  • ZXKitSwift
    是一個iOS端的調試工具的集合,跟上面的 CocoaDebug 類似

  • LookinServer
    您可以通過 Lookin 檢查和修改iOS 應用程序中的視圖桌硫,就像 Xcode 中的UI 檢查器或其他名為 Reveal 的應用程序一樣夭咬。
    簡單來說就是,集成以后铆隘,可以通過對應的軟件查看你正在運行的項目當前的層級以及控件卓舵。

    Lookin使用效果.png

開屏廣告

  • XHLaunchAd
    開屏廣告、啟動廣告解決方案-支持靜態(tài)/動態(tài)圖片廣告/mp4視頻廣告
private func setupLaunchAd() {
      XHLaunchAd.setLaunch(.launchScreen)

      let imageAdConfiguration = XHLaunchImageAdConfiguration()
      imageAdConfiguration.frame = CGRectMake(0, 0, UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height)
      imageAdConfiguration.imageNameOrURLString = "轉場動畫.gif"
      imageAdConfiguration.gifImageCycleOnce = false
      imageAdConfiguration.imageOption = .refreshCached
      imageAdConfiguration.contentMode = .scaleAspectFill
      imageAdConfiguration.openModel = "https://www.xxxx.com"
      imageAdConfiguration.showFinishAnimate = .fadein
      imageAdConfiguration.showFinishAnimateTime = 0.8
      imageAdConfiguration.skipButtonType = .roundProgressText
      imageAdConfiguration.showEnterForeground = true

      XHLaunchAd.imageAd(with: imageAdConfiguration, delegate: self)
}

數(shù)據(jù)序列化

  • HandyJSON
    HandyJSON 是一個用于 Swift 語言中的 JSON 序列化/反序列化庫
class DeviceToolModel: HandyJSON {
    
    var toolTitle: String = ""
    var toolSubtitle: [String] = [String]()
    
    required init() {
        
    }
    
    init(toolTitle: String, toolSubtitle: [String]) {
        self.toolTitle = toolTitle
        self.toolSubtitle = toolSubtitle
    }
    
}

擴展

  • SwifterSwift
    SwifterSwift 是 500 多個原生Swift 擴展的集合膀钠,為 iOS掏湾、macOStvOS肿嘲、watchOSLinux 提供了(超過 500 個)適用于各種原生數(shù)據(jù)類型忘巧、UIKitCocoa 類的便捷方法、語法糖和性能改進

  • Hue
    UIColor 的擴展

  • SwiftDate
    在Swift中解析睦刃、驗證砚嘴、操作、比較和顯示日期涩拙、時間和時區(qū)的工具包际长,很好用的!

  • SwiftyTimer
    定時器兴泥,麻麻再也不擔心我寫個定時器一大串代碼了

動畫

  • lottie-ios
    動畫庫工育,我是用來加載本地json 動畫的,可以動態(tài)修改 json 內動畫元素的顏色哦

    加載json動畫.png

  • SVGKit
    用來渲染 SVG 的搓彻,可以根據(jù)在 SVG 文件內添加的id來動態(tài)修改顏色

    svg文件內元素加id.png

這是用法:

setupSVGColors(svgName: "c0301", configs: self.setupSVGModel(colors: ["#FF0000", "#00FA9A", "#FF0000", "#FF0000"]), view: self.imageView)
setupSVGColors(svgName: "c0302", configs: self.setupSVGModel(colors: ["#FF0000", "#00FA9A", "#FF0000", "#FF0000"]), view: imageView1)
setupSVGColors(svgName: "c0303", configs: self.setupSVGModel(colors: ["#FF0000", "#00FA9A", "#FF0000", "#FF0000"]), view: imageView2)
setupSVGColors(svgName: "c0304", configs: self.setupSVGModel(colors: ["#FF0000", "#00FA9A", "#FF0000", "#FF0000"]), view: imageView3)
setupSVGColors(svgName: "c0305", configs: self.setupSVGModel(colors: ["#FF0000", "#00FA9A", "#FF0000", "#FF0000"]), view: imageView4)

這是當時為 SVG 改顏色寫的一個簡單的 model

class svgTintColorModel {
    var layerId: String = ""
    var color: String = ""
}

因為我們的 SVG 加了不同透明度如绸,所以層級會變得很多,遍歷的層級也要同步

private func setupSVGModel(colors: [String]) -> [svgTintColorModel] {
        var models = [svgTintColorModel]()
        colors.enumerated().forEach { (index, color) in
            let model = svgTintColorModel()
            model.layerId = "0\(colors.count)0\(index + 1)00"
            model.color = color
            models.append(model)
        }
        return models
    }

private func setupSVGColors(svgName: String, configs: [svgTintColorModel], view: UIImageView) {
        let svgImage = SVGKImage.init(named: svgName)
        configs.enumerated().forEach { index, config in
            svgImage?.caLayerTree.sublayers?.enumerated().forEach({ layer in
                autoreleasepool {
                    log.debug("第一層name是:\(layer.element.name ?? "")")
                    if (layer.element.name?.contains(config.layerId)) == true {
                        let shapeLayer = layer.element as! CAShapeLayer
                        shapeLayer.fillColor = UIColor.init(hex: config.color).cgColor
                        log.debug("第一層找到一個")
                    }
                    
                    layer.element.sublayers?.enumerated().forEach({ secondLayer in
                        log.debug("第二層name是:\(secondLayer.element.name ?? "")")
                        if (secondLayer.element.name?.contains(config.layerId)) == true {
                            let shapeLayer = secondLayer.element as! CAShapeLayer
                            shapeLayer.fillColor = UIColor.init(hex: config.color).cgColor
                            log.debug("第二層找到一個")
                        }
                        
                        secondLayer.element.sublayers?.enumerated().forEach({ thirdLayer in
                            log.debug("第三層name是:\(thirdLayer.element.name ?? "")")
                            if (thirdLayer.element.name?.contains(config.layerId)) == true {
                                let shapeLayer = thirdLayer.element as! CAShapeLayer
                                shapeLayer.fillColor = UIColor.init(hex: config.color).cgColor
                                log.debug("第三層找到一個")
                            }

                            thirdLayer.element.sublayers?.enumerated().forEach({ fourthLayer in
                                log.debug("第四層name是:\(fourthLayer.element.name ?? "")")
                                if (fourthLayer.element.name?.contains(config.layerId)) == true {
                                    let shapeLayer = fourthLayer.element as! CAShapeLayer
                                    shapeLayer.fillColor = UIColor.init(hex: config.color).cgColor
                                    log.debug("第四層找到一個")
                                }
                            })
                        })
                    })
                }
            })
        }
        let svgImageView = SVGKLayeredImageView.init(svgkImage: svgImage)
        view.image = svgImageView?.image.uiImage
    }
  • Hero
    用于構建iOS視圖控制器過渡的庫,重點在過渡

  • SkeletonView
    這是一種向用戶展示某事正在發(fā)生并讓他們?yōu)檎诘却膬热葑龊脺蕚涞膬?yōu)雅方式

class SkeletonViewDemoController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.addSubview(self.label)
        self.label.snp.makeConstraints { make in
            make.leading.equalTo(20)
            make.centerX.equalToSuperview()
            make.top.equalTo(100)
            make.height.equalTo(40)
        }
        
        self.view.addSubview(self.imageView)
        self.imageView.snp.makeConstraints { make in
            make.top.equalTo(self.label.snp.bottom).offset(20)
            make.width.height.equalTo(100)
            make.centerX.equalToSuperview()
        }
        
        self.label.showAnimatedGradientSkeleton()
        self.imageView.showAnimatedGradientSkeleton()
        
        Timer.after(5) {
            self.label.hideSkeleton()
            self.imageView.hideSkeleton()
        }
    }
    
    //MARK: - lazy load -
    private lazy var label: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 20)
        label.textColor = .red
        label.isSkeletonable = true
        label.text = "1f1wfagwagwag12512t3t1g1g"
        return label
    }()
    
    private lazy var imageView: UIImageView = {
        let imageView = UIImageView()
        imageView.isSkeletonable = true
        imageView.contentMode = .scaleAspectFit
        imageView.image = UIImage(named: "ic_art")
        return imageView
    }()
}

效果:


SkeletonView效果.gif

彈窗

private func popupCustomView() {
      var attributes = EKAttributes.centerFloat
      attributes.entryBackground = .color(color: EKColor(UIColor(white: 1, alpha: 1)))
      attributes.screenBackground = .color(color: EKColor(UIColor(white: 1, alpha: 1)))
      //遮罩層觸摸是忽略旭贬、轉發(fā)到窗口還是退出
      attributes.screenInteraction = .absorbTouches
      attributes.entryInteraction = .forward
      attributes.entranceAnimation = .translation
      attributes.exitAnimation = .translation
      attributes.displayDuration = .infinity
      let view = UIView()
      view.addSubview(self.poupView)
      self.poupView.snp.makeConstraints { make in
          make.center.equalToSuperview()
          make.width.equalTo(UIScreen.main.bounds.width)
          make.height.equalTo(UIScreen.main.bounds.height)
      }
      self.poupView.startAnimation()
      SwiftEntryKit.display(entry: self.poupView, using: attributes)
}

標簽欄

  • ESTabBarController-swift
    高度自定義的TabBarController組件

  • WCDB
    基于 SQLite 和 SQLCipher 開發(fā)的數(shù)據(jù)庫怔接,TX爸爸出品的,看起來很好用稀轨,正在接入試試

pod 'WCDB.cpp'
var config = SwiftMessages.Config()
config.presentationStyle = .center
config.presentationContext = .window(windowLevel: .alert)
config.prefersStatusBarHidden = true
config.duration = .forever
config.dimMode = .gray(interactive: true)
config.interactiveHide = false
SwiftMessages.show(config: config, view: self.popupView)

效果:


SwiftMessagesSegue.gif
  • Instructions
    引導視圖
    目前使用的過程中有點問題扼脐,我給控制器中央的一個view設置了引導,但是引導View卻出現(xiàn)在了狀態(tài)欄位置奋刽,被遮擋住了一部分

    QQ20230411-0.jpg

  • awesome-ios
    2024.5.31日發(fā)現(xiàn)的瓦侮,列出了大量精選的 iOS 優(yōu)秀項目列表,包括 Objective-C 和 Swift 項目佣谐,有想要找的庫可以去這個下面找找肚吏。

圖片選擇器

SwiftUI 實現(xiàn)的小控件

  • SwiftUI_Demos
    在找別的庫的時候翻到的,里面有很多動效很好的控件

圖片裁剪(框)

  • JPImageresizerView
    之前的項目中有需求裁剪圖片狭魂,要有裁剪框罚攀,并且裁剪框的大小和圓角沒有固定吁断,當時自己跌跌撞撞的寫了一個,最近逛github的時候發(fā)現(xiàn)坞生,誒仔役,這個好呀,當時怎么沒發(fā)現(xiàn)O.o
    JPImageresizerView的截圖.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末是己,一起剝皮案震驚了整個濱河市又兵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卒废,老刑警劉巖沛厨,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異摔认,居然都是意外死亡逆皮,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門参袱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來电谣,“玉大人,你說我怎么就攤上這事抹蚀〗宋” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵环壤,是天一觀的道長晒来。 經常有香客問我,道長郑现,這世上最難降的妖魔是什么湃崩? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮接箫,結果婚禮上攒读,老公的妹妹穿的比我還像新娘。我一直安慰自己列牺,他們只是感情好整陌,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瞎领,像睡著了一般。 火紅的嫁衣襯著肌膚如雪随夸。 梳的紋絲不亂的頭發(fā)上九默,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音宾毒,去河邊找鬼驼修。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的乙各。 我是一名探鬼主播墨礁,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼耳峦!你這毒婦竟也來了恩静?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤蹲坷,失蹤者是張志新(化名)和其女友劉穎驶乾,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體循签,經...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡级乐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了县匠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片风科。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖乞旦,靈堂內的尸體忽然破棺而出丐重,到底是詐尸還是另有隱情,我是刑警寧澤杆查,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布扮惦,位于F島的核電站,受9級特大地震影響亲桦,放射性物質發(fā)生泄漏崖蜜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一客峭、第九天 我趴在偏房一處隱蔽的房頂上張望豫领。 院中可真熱鬧,春花似錦舔琅、人聲如沸等恐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽课蔬。三九已至,卻和暖如春郊尝,著一層夾襖步出監(jiān)牢的瞬間二跋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工流昏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扎即,地道東北人吞获。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像谚鄙,于是被迫代替她去往敵國和親各拷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內容