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

今年年初跳槽,顺便也从 OC 转为了 Swift ,所以之前 OC 版的框架就暂时不更新了,重新写了这篇文章,是我在 Swift 开发过程中用到、或者看到,个人觉得比较好用的框架,有新的偶遇,也会更新的,有兴趣的可以去瞄一眼

内置调试工具

  • 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
    检测循环引用、内存泄漏

  • FLEX
    Star很高的在线调试工具,主要是可以不用连着Xcode实时看数据库的数据,Log 的话有一堆不需要的,但是很多需要的却没有,暂时我还不知道怎么用这个框架的 Log。cash 我写了一个数组越界,但是并不知道在哪里可以看。以下是集成:

pod 'FLEX', :configurations => ['Debug']
FLEXManager.shared.showExplorer()
  • CocoaDebug
    也是一个在线看log、crash、文件、网络请求等的框架,但是我写了很多 Log,他几乎只会显示他自己的 CocoaDebugTool.log(with: "446633"),crash 我写了一个数组越界,但是并没有抓到。以下是集成方法:
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
    开屏广告、启动广告解决方案-支持静态/动态图片广告/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)
}

数据序列化

  • 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 扩展的集合,为 iOSmacOStvOSwatchOSLinux 提供了(超过 500 个)适用于各种原生数据类型、UIKitCocoa 类的便捷方法、语法糖和性能改进

  • Hue
    UIColor 的扩展

  • SwiftDate
    在Swift中解析、验证、操作、比较和显示日期、时间和时区的工具包,很好用的!

  • SwiftyTimer
    定时器,麻麻再也不担心我写个定时器一大串代码了

动画

  • lottie-ios
    动画库,我是用来加载本地json 动画的,可以动态修改 json 内动画元素的颜色哦

    加载json动画.png

  • SVGKit
    用来渲染 SVG 的,可以根据在 SVG 文件内添加的id来动态修改颜色

    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
    这是一种向用户展示某事正在发生并让他们为正在等待的内容做好准备的优雅方式

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)))
      //遮罩层触摸是忽略、转发到窗口还是退出
      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 开发的数据库,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却出现在了状态栏位置,被遮挡住了一部分

    QQ20230411-0.jpg

  • awesome-ios
    2024.5.31日发现的,列出了大量精选的 iOS 优秀项目列表,包括 Objective-C 和 Swift 项目,有想要找的库可以去这个下面找找。

图片选择器

SwiftUI 实现的小控件

  • SwiftUI_Demos
    在找别的库的时候翻到的,里面有很多动效很好的控件
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容