博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Swift 项目总结 02 常用分类方法
阅读量:6265 次
发布时间:2019-06-22

本文共 18882 字,大约阅读时间需要 62 分钟。

PS:Xcode 版本是 Version 9.2 (9C40b),编译 Swift 版本是:3.2

NSObject+ClassName

功能:获取某个对象或者某个类的类名字符串(比如 xib 加载)

extension NSObject {        /// 返回类名字符串    static var className: String {        return String(describing: self)    }        /// 返回类名字符串    var className: String {        return String(describing: type(of: self))    }}复制代码

String+BoundingRect

功能:计算字符串在 label 上的宽高(比如 cell 自适应高度)

extension String {    /// 给定最大宽计算高度,传入字体、行距、对齐方式(便捷调用)    func heightForLabel(width: CGFloat, font: UIFont, lineSpacing: CGFloat = 5, alignment: NSTextAlignment = .left) -> CGFloat {        let paragraphStyle = NSMutableParagraphStyle()        paragraphStyle.lineSpacing = lineSpacing        paragraphStyle.alignment = alignment        let attributes: [String : Any] = [            NSFontAttributeName: font,            NSParagraphStyleAttributeName: paragraphStyle        ]        let textSize = textSizeForLabel(width: width, height: CGFloat(Float.greatestFiniteMagnitude), attributes: attributes)        return textSize.height    }        /// 给定最大宽计算高度,传入属性字典(便捷调用)    func heightForLabel(width: CGFloat, attributes: [String: Any]) -> CGFloat {        let textSize = textSizeForLabel(width: width, height: CGFloat(Float.greatestFiniteMagnitude), attributes: attributes)        return textSize.height    }        /// 给定最大高计算宽度,传入字体(便捷调用)    func widthForLabel(height: CGFloat, font: UIFont) -> CGFloat {        let labelTextAttributes = [NSFontAttributeName: font]        let textSize = textSizeForLabel(width: CGFloat(Float.greatestFiniteMagnitude), height: height, attributes: labelTextAttributes)        return textSize.width    }        /// 给定最大高计算宽度,传入属性字典(便捷调用)    func widthForLabel(height: CGFloat, attributes: [String: Any]) -> CGFloat {        let textSize = textSizeForLabel(width: CGFloat(Float.greatestFiniteMagnitude), height: height, attributes: attributes)        return textSize.width    }        /// 给定最大宽高计算宽度和高度,传入字体、行距、对齐方式(便捷调用)    func textSizeForLabel(width: CGFloat, height: CGFloat, font: UIFont, lineSpacing: CGFloat = 5, alignment: NSTextAlignment = .left) -> CGSize {        let paragraphStyle = NSMutableParagraphStyle()        paragraphStyle.lineSpacing = lineSpacing        paragraphStyle.alignment = alignment        let attributes: [String : Any] = [            NSFontAttributeName: font,            NSParagraphStyleAttributeName: paragraphStyle        ]        let textSize = textSizeForLabel(width: width, height: height, attributes: attributes)        return textSize    }        /// 给定最大宽高计算宽度和高度,传入属性字典(便捷调用)    func textSizeForLabel(size: CGSize, attributes: [String: Any]) -> CGSize {        let textSize = textSizeForLabel(width: size.width, height: size.height, attributes: attributes)        return textSize    }        /// 给定最大宽高计算宽度和高度,传入属性字典(核心)    func textSizeForLabel(width: CGFloat, height: CGFloat, attributes: [String: Any]) -> CGSize {        let defaultOptions: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]        let maxSize = CGSize(width: width, height: height)        let rect = self.boundingRect(with: maxSize, options: defaultOptions, attributes: attributes, context: nil)        let textWidth: CGFloat = CGFloat(Int(rect.width) + 1)        let textHeight: CGFloat = CGFloat(Int(rect.height) + 1)        return CGSize(width: textWidth, height: textHeight)    }}extension NSAttributedString {        /// 根据最大宽计算高度(便捷调用)    func heightForLabel(width: CGFloat) -> CGFloat {        let textSize = textSizeForLabel(width: width, height: CGFloat(Float.greatestFiniteMagnitude))        return textSize.height    }        /// 根据最大高计算宽度(便捷调用)    func widthForLabel(height: CGFloat) -> CGFloat {        let textSize = textSizeForLabel(width: CGFloat(Float.greatestFiniteMagnitude), height: height)        return textSize.width    }        /// 计算宽度和高度(核心)    func textSizeForLabel(width: CGFloat, height: CGFloat) -> CGSize {        let defaultOptions: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]        let maxSize = CGSize(width: width, height: height)        let rect = self.boundingRect(with: maxSize, options: defaultOptions, context: nil)        let textWidth: CGFloat = CGFloat(Int(rect.width) + 1)        let textHeight: CGFloat = CGFloat(Int(rect.height) + 1)        return CGSize(width: textWidth, height: textHeight)    }}复制代码

String+RegularExpression

功能:主要是简化和统一外部使用正则表达式

extension String {    /// 通过正则表达式匹配替换    func replacingStringOfRegularExpression(pattern: String, template: String) -> String {        var content = self        do {            let range = NSRange(location: 0, length: content.count)            let expression = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)            content = expression.stringByReplacingMatches(in: content, options: .reportCompletion, range: range, withTemplate: template)        } catch {            print("regular expression error")        }        return content    }        /// 通过正则表达式匹配返回结果    func matches(pattern: String) -> [NSTextCheckingResult] {        do {            let range = NSRange(location: 0, length: count)            let expression = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)            let matchResults = expression.matches(in: self, options: .reportCompletion, range: range)            return matchResults        } catch {            print("regular expression error")        }        return []    }        /// 通过正则表达式返回第一个匹配结果    func firstMatch(pattern: String) -> NSTextCheckingResult? {        do {            let range = NSRange(location: 0, length: count)            let expression = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)            let match = expression.firstMatch(in: self, options: .reportCompletion, range: range)            return match                    } catch {            print("regular expression error")        }        return nil    }}复制代码

String+Substr

功能:字符串截取快捷方法,你懂的(⊙o⊙)…

extension String {        ///  寻找在 startString 和 endString 之间的字符串    func substring(between startString: String, and endString: String?, options: String.CompareOptions = .caseInsensitive) -> String? {        let range = self.range(of: startString, options: options)        if let startIndex = range?.upperBound {            let string = self.substring(from: startIndex)            if let endString = endString {                let range = string.range(of: endString, options: options)                if let startIndex = range?.lowerBound {                    return string.substring(to: startIndex)                }            }            return string        }        return nil    }        ///  寻找 prefix 字符串,并返回从 prefix 到尾部的字符串    func substring(prefix: String, options: String.CompareOptions = .caseInsensitive, isContain: Bool = true) -> String? {        let range = self.range(of: prefix, options: options)        if let startIndex = range?.upperBound {            var resultString = self.substring(from: startIndex)            if isContain {                resultString = "\(prefix)\(resultString)"            }            return resultString        }        return nil    }        ///  寻找 suffix 字符串,并返回从头部到 suffix 位置的字符串    func substring(suffix: String, options: String.CompareOptions = .caseInsensitive, isContain: Bool = false) -> String? {        let range = self.range(of: suffix, options: options)        if let startIndex = range?.lowerBound {            var resultString = self.substring(to: startIndex)            if isContain {                resultString = "\(resultString)\(suffix)"            }            return resultString        }        return nil    }        ///  从 N 位置到尾位置的字符串    func substring(from: IndexDistance) -> String? {        let index = self.index(self.startIndex, offsetBy: from)        return self.substring(from: index)    }        ///  从头位置到 N 位置的字符串    func substring(to: IndexDistance) -> String? {        let index = self.index(self.startIndex, offsetBy: to)        return self.substring(to: index)    }        /// 以 lower 为起点,偏移 range 得到的字符串    func substring(_ lower: IndexDistance, _ range: IndexDistance) -> String? {        let lowerIndex = self.index(self.startIndex, offsetBy: lower)        let upperIndex = self.index(lowerIndex, offsetBy: range)        let range = Range(uncheckedBounds: (lowerIndex, upperIndex))        return self.substring(with: range)    }}复制代码

UIFont+Convenience

功能:除了简化自定义字体的引入外,这里可以统一管理字体大小,比如对字体大小进行统一屏幕适配

enum FontWeight: String {    case light = "Light"    case regular = "Regular"    case medium = "Medium"    case semibold = "Semibold"    case bold = "Bold"    case heavy = "Heavy"}enum FontType: String {    case PingFangSC = "PingFangSC"    case SFProText = "SFProText"}extension UIFont {        static func heavyFont(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {        return customFont(type, weight: .heavy, fontSize: fontSize)    }        static func regularFont(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {        return customFont(type, weight: .regular, fontSize: fontSize)    }        static func boldFont(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {        return customFont(type, weight: .bold, fontSize: fontSize)    }        static func lightFont(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {        return customFont(type, weight: .light, fontSize: fontSize)    }        static func mediumFont(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {        return customFont(type, weight: .medium, fontSize: fontSize)    }        static func semiboldFont(ofSize fontSize: CGFloat, type: FontType = .PingFangSC) -> UIFont {        return customFont(type, weight: .semibold, fontSize: fontSize)    }        /// 自定义字体    static func customFont(_ type: FontType, weight: FontWeight, fontSize: CGFloat) -> UIFont {        let realFontSize = fontSize        if let customFont = UIFont(name: "\(type.rawValue)-\(weight.rawValue)", size: realFontSize) {            return customFont        }        if #available(iOS 8.2, *) {
var systemWeight: CGFloat = UIFontWeightRegular switch weight { case .light: systemWeight = UIFontWeightLight case .regular: systemWeight = UIFontWeightRegular case .medium: systemWeight = UIFontWeightMedium case .semibold: systemWeight = UIFontWeightSemibold case .bold: systemWeight = UIFontWeightBold case .heavy: systemWeight = UIFontWeightHeavy } return UIFont.systemFont(ofSize: realFontSize, weight: systemWeight) } else { return UIFont.systemFont(ofSize: realFontSize) } }}复制代码

UIView+Convenience

功能:一些常用的视图操作,比如 xib 加载、截图、找响应控制器

extension UIView {        /// 从 xib 中加载视图    func loadViewFromNib(index: Int = 0) -> UIView? {        let classInstance = type(of: self)        let nibName = classInstance.className        let nib = UINib(nibName: nibName, bundle: nil)                if let views = nib.instantiate(withOwner: self, options: nil) as? [UIView] {            return views.safeIndex(index)        }        return nil    }    /// 寻找当前视图所在的控制器    var responderController: UIViewController? {        var nextReponder: UIResponder? = self.next        while nextReponder != nil {            if let viewController = nextReponder as? UIViewController {                return viewController            }            nextReponder = nextReponder?.next        }        return nil    }    /// 生成视图的截图    func displayViewToImage() -> UIImage? {        UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0)        if let context = UIGraphicsGetCurrentContext() {            self.layer.render(in: context)        }        let image = UIGraphicsGetImageFromCurrentImageContext()        UIGraphicsEndImageContext()        return image    }}复制代码

CollectionView+Convenience

功能:主要是为了简化 CollectionView 注册和从缓冲池取控件的代码

extension UICollectionView {        /// 批量注册 Cell    func registerForCells
(_ cellClasses: [T.Type], isNib: Bool = true) { cellClasses.forEach { cellClass in registerForCell(cellClass, isNib: isNib) } } /// 注册 Cell func registerForCell
(_ cellClass: T.Type, identifier: String? = nil, isNib: Bool = true) { let nibName = cellClass.className let cellIdentifier = identifier ?? nibName if isNib { self.register(UINib(nibName: nibName, bundle: nil), forCellWithReuseIdentifier: cellIdentifier) } else { self.register(cellClass, forCellWithReuseIdentifier: cellIdentifier) } } /// 注册顶部视图 func registerForHeader
(_ cellClass: T.Type, identifier: String? = nil, isNib: Bool = true) { let nibName = cellClass.className let headerIdentifier = identifier ?? nibName if isNib { self.register(UINib(nibName: nibName, bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier) } else { self.register(cellClass, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier) } } /// 注册底部视图 func registerForFooter
(_ cellClass: T.Type, identifier: String? = nil, isNib: Bool = true) { let nibName = cellClass.className let footerIdentifier = identifier ?? nibName if isNib { self.register(UINib(nibName: nibName, bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: footerIdentifier) } else { self.register(cellClass, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: footerIdentifier) } } /// 从缓存池取出 Cell func dequeueCell
(_ cellClass: T.Type, reuseIdentifier: String? = nil, indexPath: IndexPath) -> T { let identifier: String = reuseIdentifier ?? cellClass.className if let cell = dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as? T { return cell } else { return T() } } /// 从缓存池取出顶部或者底部实体 func dequeueSupplementaryView
(_ viewClass: T.Type, kind: String, indexPath: IndexPath) -> T { let identifier = viewClass.className if let cell = dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: identifier, for: indexPath) as? T { return cell } else { return T() } } /// 滑动到第一个 Cell 位置,通过增加判断,防止奔溃 func scrollToFirstCell(animated: Bool = true) { guard self.numberOfSections > 0 else { return } guard let count = self.dataSource?.collectionView(self, numberOfItemsInSection: 0) else { return } if count > 0 { if let flowLayout = self.collectionViewLayout as? UICollectionViewFlowLayout { if flowLayout.scrollDirection == .horizontal { scrollToItem(at: IndexPath(row: 0, section: 0), at: .left, animated: animated) } else { scrollToItem(at: IndexPath(row: 0, section: 0), at: .top, animated: animated) } } } }}复制代码

Array+Convenience

功能:数组便捷操作,其中 safeIndex 是为了防止数组越界,双边遍历的需求是为了优化显示图片列表加载,从用户当前看到的图片开始向两边加载

extension Array {        /// 获取数组中的元素,增加了数组越界的判断    func safeIndex(_ i: Int) -> Array.Iterator.Element? {        guard !isEmpty && self.count > abs(i) else {            return nil        }                for item in self.enumerated() {            if item.offset == I {                return item.element            }        }        return nil    }        /// 从前面取 N 个数组元素    func limit(_ limitCount: Int) -> [Array.Iterator.Element] {        let maxCount = self.count        var resultCount: Int = limitCount        if maxCount < limitCount {            resultCount = maxCount        }        if resultCount <= 0 {            return []        }        return self[0..
[Array.Iterator.Element] { var items = self while items.count > 0 && items.count < fullCount { items = (items + items).limit(fullCount) } return items.limit(fullCount) } /// 双边遍历,从中间向两边进行遍历 func bilateralEnumerated(_ beginIndex: Int, handler: (Int, Array.Iterator.Element) -> Void) { let arrayCount: Int = self.count var leftIndex: Int = Swift.max(0, Swift.min(beginIndex, arrayCount - 1)) var rightIndex: Int = leftIndex + 1 var currentIndex: Int = leftIndex var isLeftEnable: Bool = leftIndex >= 0 && leftIndex < arrayCount var isRightEnable: Bool = rightIndex >= 0 && rightIndex < arrayCount var isLeft: Bool = isLeftEnable ? true : isRightEnable while isLeftEnable || isRightEnable { currentIndex = isLeft ? leftIndex : rightIndex if let element = self.safeIndex(currentIndex) { handler(currentIndex, element) } if isLeft { leftIndex -= 1 } else { rightIndex += 1 } isLeftEnable = leftIndex >= 0 && leftIndex < arrayCount isRightEnable = rightIndex >= 0 && rightIndex < arrayCount if isLeftEnable && !isRightEnable { isLeft = true } else if !isLeftEnable && isRightEnable { isLeft = false } else if isLeftEnable && isRightEnable { isLeft = !isLeft } } }}复制代码

NSDictionary+Convenience

功能:简化从字典中取值的代码,并支持多键查找

extension NSDictionary {        // MARK: - 以下都是从字典里取值的快捷方法,支持多键查找和默认返回    func bool(_ keys: String..., defaultValue: Bool = false) -> Bool {        return valueForKeys(keys, type: Bool.self) ?? defaultValue    }        func double(_ keys: String..., defaultValue: Double = 0.0) -> Double {        return valueForKeys(keys, type: Double.self) ?? defaultValue    }        func int(_ keys: String..., defaultValue: Int = 0) -> Int {        return valueForKeys(keys, type: Int.self) ?? defaultValue    }        func string(_ keys: String..., defaultValue: String? = nil) -> String? {        return valueForKeys(keys, type: String.self) ?? defaultValue    }        func dictionary(_ keys: String..., defaultValue: NSDictionary? = nil) -> NSDictionary? {        return valueForKeys(keys, type: NSDictionary.self) ?? defaultValue    }        func array
(_ keys: String..., type: T.Type, defaultValue: [T] = []) -> [T] { return valueForKeys(keys, type: Array
.self) ?? defaultValue } // MARK: - 以下是从字典里取值的核心方法,支持多键查找 fileprivate func valueForKeys
(_ keys: [String], type: T.Type) -> T? { for key in keys { if let result = self[key] as? T { return result } } return nil }}复制代码

Demo 源代码在这:

这些分类方法都是我在项目中比较常用的,能简化很多代码,希望你们喜欢!O(∩_∩)O哈哈~

转载于:https://juejin.im/post/5b126ea6f265da6e363c88c6

你可能感兴趣的文章
几个gcc的扩展功能
查看>>
Spark一个简单案例
查看>>
关于结构体占用空间大小总结(#pragma pack的使用)
查看>>
通过浏览器查看nginx服务器状态配置方法
查看>>
shell简介
查看>>
android 使用WebView 支持播放优酷视频,土豆视频
查看>>
怎么用secureCRT连接Linux
查看>>
C# 使用WinRar命令压缩和解压缩
查看>>
linux学习笔记一----------文件相关操作
查看>>
Mono for Android 优势与劣势
查看>>
服务器端开发技术
查看>>
Python3中urllib详细使用方法(header,代理,超时,认证,异常处理)
查看>>
ajax提交多个对象,使用序列化表单和FormData
查看>>
深入分析由前序和中序重构二叉树问题
查看>>
leetcode 题解 || Valid Parentheses 问题
查看>>
将图片转成base64字符串并在JSP页面显示的Java代码
查看>>
什么是WeakHashMap--转
查看>>
js 面试题
查看>>
第二十二节,三元运算
查看>>
Yacc 与 Lex 快速入门
查看>>