Swift:NSObject 扩展工具箱

原创:问题解决型文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容

目录

  • 1、Array 的扩展
  • 2、Date 的扩展
  • 3、Dictionary 的扩展
  • 4、Int 的扩展
  • 5、NSMutableAttributedString 的扩展
  • 6、NSData 的扩展
  • 7、NSObject 的扩展
  • 8、Double 的扩展
  • 9、Float 的扩展
  • 10、CGFloat 的扩展
  • 11、String 的扩展
  • 12、Timer 的扩展

1、Array 的扩展

public extension Array
arrayJsonString():将数组对象转换成json字符串
func arrayJsonString() -> String? {
    if !JSONSerialization.isValidJSONObject(self) {
        return nil
    }
    if let data = try? JSONSerialization.data(withJSONObject: self, options: []),
       let string =  NSString(data: data, encoding: String.Encoding.utf8.rawValue){
        return string as String
    }
    return nil
}
eachItem(_ callback:((Int, Any)->Void)):遍历返回index和item
openWhiteList.eachItem { (index, item) in
    
}
func eachItem(_ callback:((Int, Any)->Void)) {
    for (index,value) in self.enumerated() {
        callback(index,value)
    }
}
reduceArray(_ array:[Any], block:((Any) -> Bool)?):过滤数组
/// block: 过滤器回调方法
func reduceArray(_ array:[Any], block:((Any) -> Bool)?) -> [Any]? {
    var result = array
    if block != nil {
        for (_,item) in self.enumerated() {
            if (block!(item)) {
                result.append(item)
            }
        }
    } else {
        result.append(contentsOf: self)
    }
    return result
}
firstRuleNumber(block: (Any) -> Bool):获取数组中符合规则的第一个数据
func firstRuleNumber(block: (Any) -> Bool) -> Any? {
    for (_,item) in self.enumerated() {
        if (block(item)) {
            return item
        }
    }
    return nil
}

2、Date 的扩展

public extension Date
secondsPerDay:每天有多少秒
var secondsPerDay: TimeInterval {
    get {
        return 24 * 60 * 60
    }
}
secondsPerHour:每小时有多少秒
var secondsPerHour: TimeInterval {
    get {
        return 60 * 60
    }
}
secondsPerMinute:每分钟有多少秒
var secondsPerMinute: TimeInterval {
    get {
        return 60
    }
}
yesterday:昨天
var yesterday: Date {
    get {
        return self.addingTimeInterval(-secondsPerDay)
    }
}
tomorrow:明天
var tomorrow: Date {
    get {
        return self.addingTimeInterval(secondsPerDay)
    }
}
lastWeek:上周
var lastWeek: Date {
    get {
        return self.addingTimeInterval(-secondsPerDay * 7)
    }
}
lastThirtyDays:上个月
var lastThirtyDays: Date {
    get {
        return self.addingTimeInterval(-secondsPerDay * 30)
    }
}
latest(_ day: Int) -> Date:获取间隔一定天数的日期(时间间隔可以是正数或负数)
func latest(_ day: Int) -> Date {
    return self.addingTimeInterval(secondsPerDay * Double(day))
}
lastestMonth(_ month: Int) -> Date?:获取间隔一定月份的日期
func lastestMonth(_ month: Int) -> Date? {
    var comps = DateComponents()
    comps.month = month
    if let calender = NSCalendar(calendarIdentifier: .gregorian) {
        let mDate = calender.date(byAdding: comps, to: self, options: NSCalendar.Options(rawValue: 0))
        return mDate
    }
    return nil
}
获取年月日时分秒
var year: Int {
    return Calendar.current.dateComponents([.year], from: self).year ?? 0  // 默认0点
}
var month: Int {
    return Calendar.current.dateComponents([.month], from: self).month ?? 0  // 默认0点
}
var day: Int {
    return Calendar.current.dateComponents([.day], from: self).day ?? 0  // 默认0点
}
var hour: Int {
    return Calendar.current.dateComponents([.hour], from: self).hour ?? 0  // 默认0点
}
var minute: Int {
    return Calendar.current.dateComponents([.minute], from: self).minute ?? 0  // 默认0点
}
var second: Int {
    return Calendar.current.dateComponents([.second], from: self).second ?? 0  // 默认0点
}
timeIntervalDay:获取距离当前时间的天数

self晚于当前时间24小时整数倍时,返回结果为负数,并且比实际时间长度绝对值小1。时间比较是以毫秒维度比较的,代码执行顺序会产生时间差异,这种情况建议手动处理。

var timeIntervalDay: Int {
    return Calendar.current.dateComponents([.day], from: self, to: Date()).day ?? 0  // 默认0点
}
isBetweenFormHour(_ formHour:NSInteger,toHour:NSInteger):判断当前时间是否在两个时间段内
func isBetweenFormHour(_ formHour:NSInteger,toHour:NSInteger) -> Bool {
    let dateFrom = self.getCustomDateWith(hour: formHour)
    let dateTo = self.getCustomDateWith(hour: toHour)
    
    let currentDate = self
    if (currentDate.compare(dateFrom) == .orderedDescending || currentDate.compare(dateFrom) == .orderedSame) && (currentDate.compare(dateTo) == .orderedAscending || currentDate.compare(dateTo) == .orderedSame){
        return true
    }
    return false
}
getCustomDateWith(hour:NSInteger) -> Date:根据小时获取自定义日期
private func getCustomDateWith(hour:NSInteger) -> Date {
    let currentDate = self
    let currentCalendar = Calendar.init(identifier: .gregorian)
    var currentComps = DateComponents()
    currentComps = currentCalendar.dateComponents([Calendar.Component.year,Calendar.Component.month,Calendar.Component.day,Calendar.Component.weekday,Calendar.Component.hour,Calendar.Component.month,Calendar.Component.second], from: currentDate)
    
    var resultComps = DateComponents()
    resultComps.year = currentComps.year
    resultComps.month = currentComps.month
    resultComps.day = currentComps.day
    resultComps.hour = hour
    resultComps.minute = currentComps.minute
    
    let resultCalendar = Calendar.init(identifier: .gregorian)
    return resultCalendar.date(from: resultComps)!
}
standerTimeString():标准时间格式 yyyy-MM-dd
func standerTimeString() ->String {
    let formate = DateFormatter()
    formate.dateFormat = "yyyy-MM-dd"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
standerTimeString():发表时间格式 MM-dd HH:mm
func publishTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "MM-dd HH:mm"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
standerTimeString():草稿时间格式 yyyy.MM.dd HH:mm
func draftTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "yyyy.MM.dd HH:mm"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
detailTimeString():详情时间格式 yyyy-MM-dd HH:mm
func detailTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "yyyy-MM-dd HH:mm"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
yyyymmdd():时间格式 yyyy.MM.dd
func yyyymmdd() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "yyyy.MM.dd"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
yearTimeString():只有年时间格式 yyyy
func yearTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "yyyy"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
yearTimeString():只有月时间格式 MM
func monthTimeString() ->String {
    let formate = DateFormatter()
    formate.dateFormat = "MM"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
dayTimeString():只有天时间格式 dd
func dayTimeString() ->String {
    let formate = DateFormatter()
    formate.dateFormat = "dd"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
hourTimeString():只有小时时间格式 HH
func hourTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "HH"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
minuteTimeString():只有分钟时间格式 mm
func minuteTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "mm"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
secondTimeString():只有秒时间格式 ss
func secondTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "ss"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
hhmmssString():时分秒时间格式 HH:mm:ss
func hhmmssString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "HH:mm:ss"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
todayPublishTimeString():今天发布的时间格式 HH:mm
func todayPublishTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "HH:mm"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
liveStartTimeString():带中文的时间格式 MM月dd日 EEE HH:mm
func liveStartTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "MM月dd日 EEE HH:mm"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
weekTimeString():周时间格式 EEE
func weekTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "EEE"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
monthDayTimeString():月天时间格式 MM/dd
func monthDayTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "MM/dd"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
monthDayUnderLineTimeString():月天下划线时间格式 MM-dd
func monthDayUnderLineTimeString() -> String {
    let formate = DateFormatter()
    formate.dateFormat = "MM-dd"
    formate.locale = NSLocale.current
    let str = formate.string(from: self)
    return str
}
yearAndMonthString():年月时间格式 YYYY年MM月
func yearAndMonthString() -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "YYYY年MM月"
    formatter.locale = NSLocale.current
    let str = formatter.string(from: self)
    return str
}
weekString():星期时间格式 星期
func weekString() -> String {
    let comp = Calendar.current.dateComponents([.weekday], from: self)
    let week = comp.weekday ?? 1
    var weekDayStr = ""
    switch (week) {
    case 1:
        weekDayStr = "星期日";
        break;
    case 2:
        weekDayStr = "星期一";
        break;
    case 3:
        weekDayStr = "星期二";
        break;
    case 4:
        weekDayStr = "星期三";
        break;
    case 5:
        weekDayStr = "星期四";
        break;
    case 6:
        weekDayStr = "星期五";
        break;
    case 7:
        weekDayStr = "星期六";
        break;
    default:
        weekDayStr = "";
        break;
    }
    return weekDayStr;
}
dateDisplayString():根据日期比较显示时间格式,从年月日开始比对,隐藏相同项
func dateDisplayString() -> String {
    let nowComponents = Calendar.current.dateComponents([.year, .month, .day], from: Date())
    let selfComponents = Calendar.current.dateComponents([.year, .month, .day], from: self)

    if nowComponents.year == selfComponents.year &&
        nowComponents.month == selfComponents.month &&
        nowComponents.day == selfComponents.day {// 同天
        return todayPublishTimeString()
    }

    if nowComponents.year == selfComponents.year {// 同年
        return self.monthDayUnderLineTimeString()
    } else {// 不同年
        return self.yearTimeString()
    }
}
timeDisplayString():根据日期比较显示时间格式,细化到当天、昨天
func timeDisplayString() -> String {
    if Calendar.current.isDateInToday(self) {// 当天: 时间段 + 00:00 - 23:59
        return todayPublishTimeString()
    } else if Calendar.current.isDateInYesterday(self) {// 昨天 时间段 + 00:00 - 23:59
        let time = todayPublishTimeString()
        return "昨天 \(time)"
    } else {
        let now = Date()
        let interval = now.timeIntervalSince(self)
        
        // 超过48小时: 星期几 + 时间段 + 00:00 - 23:59
        if interval > 3600 * 24 * 2 &&  interval < 3600 * 24 * 7  {
            let time = todayPublishTimeString()
            let week = weekString()
            return "\(week) \(time)"
        }
        
        // 超过一周: xxxx年xx月xx日 + 时间段 + 时间段 + 00:00 - 23:59       
        return detailTimeString()
    }
}
timeIntervalChangeToTimeString(timeInterval:TimeInterval, dateFormat:String?):时间戳转成字符串
func timeIntervalChangeToTimeString(timeInterval:TimeInterval, dateFormat:String?) -> String {
    let date:NSDate = NSDate.init(timeIntervalSince1970: timeInterval)
    let formatter = DateFormatter.init()
    if dateFormat == nil {
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    } else {
        formatter.dateFormat = dateFormat
    }
    return formatter.string(from: date as Date)
}
intelligentDisplayString():NSDate的智能文本输出
func intelligentDisplayString() -> String {
    let now = Date()
    let interval = now.timeIntervalSince(self)
    
    if interval < 60 {// 60秒之内显示刚刚
        return "刚刚"
    }
    if interval >= 60 && interval < 3600 {// 1小时之内显示n分钟前
        return "\(Int(interval / 60))分钟前"
    }
    if interval >= 3600 && interval < 3600 * 24 {// 1天之内显示n小时前
        return "\(Int(interval / 3600))小时前"
    }

    let nowComponents = Calendar.current.dateComponents([Calendar.Component.year], from: now)
    let selfComponents = Calendar.current.dateComponents([Calendar.Component.year], from: self)
    if nowComponents.year == selfComponents.year {// 本年度显示MM-dd
        return monthDayUnderLineTimeString()
    } else {// 非本年显示YYYY-MM-dd
        return standerTimeString()
    }
}
getDate(dateStr: String, format: String):自定义日期格式
static func getDate(dateStr: String, format: String) -> Date? {
    let dateFormatter = DateFormatter()
    dateFormatter.locale = Locale.current
    dateFormatter.timeZone = TimeZone.current
    dateFormatter.dateFormat = format
    let date = dateFormatter.date(from: dateStr)
    return date
}
format(to format: String):自定义日期格式
func format(to format: String) -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = format
    return formatter.string(from: self)
}
timestamp: TimeInterval:获取时间戳
var timestamp: TimeInterval {
    return self.timeIntervalSince1970
}
isSameDay (date1: Date?, date2: Date?):是否同一天
static func isSameDay (date1: Date?, date2: Date?) -> Bool {
    guard date1 != nil else {return false}
    guard date2 != nil else {return false}
    
    let calendar = Calendar.current
    let comp1 = calendar.dateComponents([.year, .month, .day], from: date1!)
    let comp2 = calendar.dateComponents([.year, .month, .day], from: date2!)
    return comp1.year == comp2.year && comp1.month == comp2.month && comp1.day == comp2.day
}

3、Dictionary 的扩展

public extension Dictionary
jsonDictionaryString():字典转JSON
func jsonDictionaryString() -> String? {
    if !JSONSerialization.isValidJSONObject(self) {
        return nil
    }
    if let data = try? JSONSerialization.data(withJSONObject: self, options: []),
       let string =  NSString(data: data, encoding: String.Encoding.utf8.rawValue){
        return string as String
    }
    return nil
}
has(key: Key):判断是否包含key
func has(key: Key) -> Bool {
    return index(forKey: key) != nil
}
removeAll(keys: [Key])
mutating func removeAll(keys: [Key]) {
    keys.forEach({ removeValue(forKey: $0)})
}
mergeWith(_ newDic:[Key:Value]):合并字典,返回新的字典,相同key值会被newDic中的value覆盖
func mergeWith(_ newDic:[Key:Value]) -> [Key:Value] {
    var result = self
    newDic.forEach { result[$0] = $1 }
    return result
}
appendWith(_ newDic:[Key:Value]):添加新字典到当前字典,不返回新字典
mutating func appendWith(_ newDic:[Key:Value]) {
    newDic.forEach { self[$0] = $1 }
}

4、Int 的扩展

Int64
public extension Int64
var number:Int64 = 8008
var str =  number.ml_numToString()// 8k
number = 8808
str = number.ml_numToString()// 8.8k
numToString():数字显示格式
func numToString() -> String{
    let num = Double(self)
    if num < 0.0 {
        return String(0)
    }
    switch num {
    case 0...999:
        let numString = String(format: "%.0f", num)
        return "\(numString)"
    case 1000...9999:
        var numString = String(format: "%.1f", num/1000)
        if numString.hasSuffix(".0") {
            numString = numString[0..<Int(numString.ml_length - 2)]
        }
        return "\(numString)k"
    default:
        var numString = String(format: "%.1f", num/10_000)
        if numString.hasSuffix(".0") {
            numString = numString[0..<Int(numString.ml_length - 2)]
        }
        return "\(numString)w"
    }
}
Int32
public extension Int32
numToString():数字显示格式
func numToString() -> String {
    let int64 = Int64(self)
    return int64.numToString()
}
Int
public extension Int
numToString():数字显示格式
func numToString() -> String {
    let int64 = Int64(self)
    return int64.numToString()
}
secondToRecordString():时间显示格式
var time = 99.ml_secondToRecordString()// 00:01:39
time = 9.ml_secondToRecordString()// 00:00:09
func secondToRecordString() -> String {
    var tmphh = "\(self / 3600)" as NSString
    if tmphh.length == 1 {
        tmphh = NSString(format: "0%@", tmphh)
    }
    var tmpmm = "\((self/60)%60)" as NSString
    if tmpmm.length == 1 {
        tmpmm = NSString(format: "0%@", tmpmm)
    }
    var tmpss = "\(self%60)" as NSString
    if tmpss.length == 1 {
        tmpss = NSString(format: "0%@", tmpss)
    }
    return NSString(format: "%@:%@:%@",tmphh,tmpmm,tmpss) as String
}
random:得到一个Int随机数,0到Int类型最大值
public static var random: Int {
    get {
        return Int.random(withMax: Int.max)
    }
}
random(withMax n: Int):获取一个0到n-1的Int随机数
public static func random(withMax n: Int) -> Int {
    return Int(arc4random_uniform(UInt32(n)))
}
random(lower min: Int, upper max: Int) -> Int:获取一个min到max的Int随机数
public static func random(lower min: Int, upper max: Int) -> Int {
    return Int.random(withMax: max - min + 1) + min
}

5、NSMutableAttributedString 的扩展

public  extension NSMutableAttributedString
attributenStringColor:选中字体颜色变红
//text: 所有字符串
//selectedText: 需要变颜色的字符串
//allColor: 字符串本来颜色
//selectedColor: 选中字符串颜色
//font: 字符串字体大小
//selectedFont: 选中字符串字体大小
static func attributenStringColor(text:String,
                             selectedText: String,
                             allColor: UIColor,
                             selectedColor: UIColor,
                             font: UIFont,
                             selectedFont:UIFont)->NSMutableAttributedString{
    var rangeArray: [NSRange] = [NSRange]()
    var lastLength: Int = 0
    let attStr = NSMutableAttributedString.init(string: text, attributes: [NSAttributedString.Key.font :  font,NSAttributedString.Key.foregroundColor:allColor])
    var text = text as NSString
    
    while text.contains(selectedText) {
        let rang: NSRange =  text.range(of: selectedText)
        let rang2 = NSMakeRange(rang.location + lastLength, rang.length)
        rangeArray.append(rang2)
        lastLength += (rang.length + rang.location )
        text = text.substring(from: rang.length + rang.location) as NSString
    }
    
    for range1 in rangeArray {
        attStr.setAttributes([NSAttributedString.Key.foregroundColor:selectedColor,NSMutableAttributedString.Key.font: selectedFont], range: range1)
    }
    
    return attStr
}
attributenStringColor:选中字体颜色变红
//text: 整体字符串
//lineSpace: 行间距
//font: 字图
static func lineSpace(text: String,lineSpace: CGFloat,font: CGFloat)->NSMutableAttributedString {
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = lineSpace
    let attStr = NSMutableAttributedString.init(string: text, attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: font)])
    attStr.addAttributes([NSAttributedString.Key.paragraphStyle : paragraphStyle], range: NSMakeRange(0, text.count))
    return attStr
}

6、NSData 的扩展

public  extension NSData
writeImageDataTofolder:将数据写入到本地文件
enum FolderType: String {
    case pickImage = "pickImage"
}
func writeTofolder(_ folderType: FolderType = .pickImage , _ name: String = "", _ nameType:String = ".png") -> String {
    guard let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentationDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first else {
        return ""
    }
    let savePath = docPath + "/" + folderType.rawValue
    if !FileManager.default.fileExists(atPath: savePath) {

        do {
            try FileManager.default.createDirectory(atPath: savePath, withIntermediateDirectories: true, attributes: nil)
        } catch {
            return ""
        }
    }
    let saveName = name.isEmpty ? ("\(Date().timeIntervalSince1970)" as NSString).replacingOccurrences(of:".", with: "") : name
    let path = savePath + "/" + "\(saveName)" + nameType
    self.write(toFile: path, atomically: true)
    return path
}

7、NSObject 的扩展

public  extension NSObject
fullClassName():完整类名
class func fullClassName() -> String {
    return NSStringFromClass(self)
}
className():类名
class func className() -> String {
    let className = NSStringFromClass(self)
    if let location = className.range(of: ".")?.upperBound {
        return String(className[location...])
    }
    return className
}

8、Double 的扩展

public extension Double
random:得到一个0到1.0的Double随机数(包括1.0)
public static var random:Double {
    get {
        return Double(arc4random()) / 0xFFFFFFFF
    }
}
random(lower min: Double, upper max: Double):获取一个min到max的Double随机数
public static func random(lower min: Double, upper max: Double) -> Double {
    return Double.random * (max - min) + min
}

9、Float 的扩展

public extension Float
random:得到一个0到1.0的Float随机数(包括1.0)
public static var random:Float {
    get {
        return Float(arc4random()) / 0xFFFFFFFF
    }
}
random(lower min: Float, upper max: Float):获取一个min到max的Float随机数
public static func random(lower min: Float, upper max: Float) -> Float {
    return Float.random * (max - min) + min
}

10、CGFloat 的扩展

extension CGFloat
randomSign:随机获得-1.0或者1.0
public static var randomSign:CGFloat {
    get {
        return (arc4random_uniform(2) == 0) ? 1.0 : -1.0
    }
}
random:得到一个0到1.0的CGFloat随机数(包括1.0)
public static var random:CGFloat {
    get {
        return CGFloat(Float.random)
    }
}
random(lower min: CGFloat, upper max: CGFloat):获取一个min到max的CGFloat随机数
public static func random(lower min: CGFloat, upper max: CGFloat) -> CGFloat {
    return CGFloat.random * (max - min) + min
}

11、String 的扩展

字符串内容判断
isEmpty(str: String?):静态方法判断字符串为空
static func isEmpty(str: String?) -> Bool {
    guard let v = str else {
        return true
    }
    let leftText = v.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
    if leftText == "" {
        return true
    }
    return false
}
isEmptyString() -> Bool:判断字符串为空
func isEmptyString() -> Bool {
    let leftText = trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
    if leftText == "" {
        return true
    }
    return false
}
isMobile() -> Bool:判断是否为手机号
func isMobile() -> Bool {
    let regex = try! NSRegularExpression(pattern: "^1[0-9]{10}$", options: [.caseInsensitive])
    return regex.firstMatch(in: self, options:[], range: NSMakeRange(0, self.count)) != nil
}
isEmail() -> Bool:校验邮箱是否合规
func isEmail() -> Bool {
    let regex = try! NSRegularExpression(pattern: "^(([a-z0-9_-]+\\.)*)([a-z0-9_-]+)@(([a-z0-9-]+\\.)+)([a-z0-9]{2,6})$", options: [.caseInsensitive])
    return regex.firstMatch(in: self, options:[], range: NSMakeRange(0, self.count)) != nil
}
isVerifyCode() -> Bool:校验验证码是否合规
func isVerifyCode() -> Bool {
    let regex = try! NSRegularExpression(pattern: "^[0-9]{6}$", options: [.caseInsensitive])
    return regex.firstMatch(in: self, options:[], range: NSMakeRange(0, self.count)) != nil
}
vaildPassword() -> (bool: Bool, error: String):校验密码是否合规
func vaildPassword() -> (bool: Bool, error: String) {
    if self.count < 6 || self.count > 16{
        return (false,"密码长度应该为6到16位")
    }
    else if self.contains(" "){
        return (false,"密码不能包含空格")
    }
    else if self.contains("\t"){
        return (false,"密码不能包含制表符")
    }
    else if self.contains("\n"){
        return (false,"密码不能包含回车")
    }
    else{
        return (true,"")
    }
}
containMobile() -> Bool:校验手机号是否合规
func containMobile() -> Bool {
    guard let regex = try? NSRegularExpression(pattern: "1[3-8][0-9]{9}", options: [.caseInsensitive]) else {return false}
    let matchNum = regex.numberOfMatches(in: self, options: [], range: NSRange(location: 0, length: (self as NSString).length))
    return matchNum > 0
}
isChinese() -> Bool:校验是否为中文
func isChinese() -> Bool {
    let regex = try! NSRegularExpression(pattern: "^[\\u4e00-\\u9fa5]+$", options: [.caseInsensitive])
    return regex.firstMatch(in: self, options:[], range: NSMakeRange(0, self.count)) != nil
}
validateIDCardNumber() -> Bool:验证身份证是否合规
func validateIDCardNumber() -> Bool {
    let value = self.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
    let length = value.count
    if (length == 18) {
        let provinceCodeList = ["11","12","13","14","15",
                            "21","22","23",
                            "31","32","33","34","35","36","37",
                            "41","42","43","44","45","46",
                            "50","51","52","53","54",
                            "61","62","63","64","65",
                            "71",
                            "81","82",
                            "91"]
        let regularExpress = try? NSRegularExpression.init(pattern: "^[0-9]{17}[0-9X]$", options: .caseInsensitive)
        if let _ = regularExpress?.firstMatch(in: self, options: .reportProgress, range: NSMakeRange(0, length)) {
            
            // 校验省份是否合规
            let province = self.subString(to: 2)
            if !provinceCodeList.contains(province) {
                return false
            }
            
            //判断年月日是否有效
            //年份
            let strYear = Int(self.subString(from: 6, length: 4))
            
            //月份
            let strMonth = Int(self.subString(from: 10, length: 2))
            
            //日
            let strDay = Int(self.subString(from: 12, length: 2))

            let localZone = NSTimeZone.local

            let dateFormatter = DateFormatter()
            dateFormatter.dateStyle = .medium
            dateFormatter.timeStyle = .none
            dateFormatter.timeZone = localZone
            dateFormatter.dateFormat = "yyyy-MM-dd"
            let date = dateFormatter.date(from: "\(String(format: "%02d",strYear!))-\(String(format: "%02d",strMonth!))-\(String(format: "%02d",strDay!))")

            if date == nil {
                return false
            }
            //加权因子
            let R = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
            
            //校验码
            let sChecker: [Int8] = [1,0,10,9,8,7,6,5,4,3,2]
            var sum = 0
            for i in 0...16 {
                sum += R[i]*(Int(self.subString(from: i, length: 1)) ?? 0)
            }
            let verifyStr = self.subString(from: 17, length: 1)
            var verifyCode = 0
            if verifyStr == "X" {
                verifyCode = 10
            } else {
                verifyCode = Int(verifyStr) ?? 0
            }
            let mode = sum % 11
            if sChecker[mode] == verifyCode {
                return true
            } else {
                return false
            }
            
        } else {
            return false
        }
    } else {
        return false
    }
}
字符串操作
subString(to:Int):截取字符串直到指定终点
func subString(to:Int) -> String {
    return subString(from: 0,to: to )
}
subString(from:Int) :从指定起点开始截取字符串
func subString(from:Int) -> String {
    return subString(from: from,to: self.count - 1)
}
subString(from:Int,length:Int):从指定起点开始截取一定长度的字符串
func subString(from:Int,length:Int) -> String {
    let to = from + length
    return subString(from: from,to: to)
}
subString(from:Int,to:Int):截取从指定起点到指定终点范围之内的字符串
func subString(from:Int,to:Int) -> String {
    if from >= self.count || to > self.count {
        return self
    } else {
        let startIndex = Index(utf16Offset: from, in: self)
        let endIndex = Index(utf16Offset: to, in: self)
        let subString = self[startIndex ..< endIndex]
        return String(subString)
    }
}
limitString(limit: Int):根据指定长度截取字符串
func limitString(limit: Int) -> String {
    return subString(to: limit)
}
limitStringWithDot(limit: Int) :根据指定长度截取字符串结尾显示...
func limitStringWithDot(limit: Int) -> String {
    let newStr = NSMutableString(string: self)
    if limit > -1 && newStr.length > limit {
        return newStr.substring(to: limit) + "..."
    } else {
        return self
    }
}
deleteSpace():删除空格
func deleteSpace() -> String {
    return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
removeAllSpace():移除所有空格
func removeAllSpace() -> String {
    return self.replacingOccurrences(of: " ", with: "", options: .literal, range: nil)
}
deleteLineBreak() :移除所有换行符和制表符
func deleteLineBreak() -> String {
    return self.replacingOccurrences(of: "\n", with: " ").replacingOccurrences(of: "\r", with: " ")
}
trimmingSpace():截取掉字符串两端的空格和换行符
func trimmingSpace() -> String {
    return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
replaceAllSpace(replacement:String = ""):替换掉字符串中所有空格,默认为移除
func replaceAllSpace(replacement:String = "") -> String {
    return self.replacingOccurrences(of: " ", with: replacement, options: .literal, range: nil)
}
replaceLineBreak(replacement:String = " "):替换掉字符串中所有换行符,默认为空格
func replaceLineBreak(replacement:String = " ") -> String {
    return self.replacingOccurrences(of: "\n", with: replacement).replacingOccurrences(of: "\r", with: replacement)
}
decodeUrl():URL解码
func decodeUrl() -> String {
    let mutStr = NSMutableString(string: self)
    mutStr.replaceOccurrences(of: "+", with: " ", options: NSString.CompareOptions.literal, range: NSMakeRange(0, mutStr.length))
    return mutStr.removingPercentEncoding ?? ""
}
encodeUrl():URL编码
func encodeUrl() -> String {
    let generalDelimitersToEncode = "!$&'()*+,;=:#[]@/?"
    var allowedCharacterSet = CharacterSet.urlQueryAllowed
    allowedCharacterSet.remove(charactersIn: generalDelimitersToEncode)
    return self.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? ""
}
urlSetComponents(_ params:[String:String]):URL 字符串拼接
func urlSetComponents(_ params:[String:String]) -> String {
    var queryItems = [URLQueryItem]()
    params.each { (key, value) in
        let queryItem = URLQueryItem(name: key, value: "\(value)")
        queryItems.append(queryItem)
    }
    let urlComponents = NSURLComponents(string: self)
    urlComponents?.queryItems = queryItems
    
    return urlComponents?.url?.absoluteString ?? ""
}
urlParameters():从urlString中截取出参数,参数必须经过url编码
func urlParameters() -> [String: String]? {
    guard let url = URL(string: self),
        let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
        let queryItems = components.queryItems else { return nil }
    return queryItems.reduce(into: [String: String](), { (result, item) in
        result[item.name] = item.value?.decodeUrl()
    })
}
rangesOfRegex(_ regex: String):获取指定正则条件的range数组
func rangesOfRegex(_ regex: String) -> [NSRange] {
    let expression = try? NSRegularExpression(pattern: regex, options: .caseInsensitive)
    let matches = expression?.matches(in: self, options: .reportProgress, range: NSMakeRange(0, self.count))
    return matches?.map({ (match) -> NSRange in
        return match.range
    }) ?? []
}
rangesOfString(_ target: String):获取指定字符串的range数组
func rangesOfString(_ target: String) -> [NSRange] {
    return self.rangesOfRegex(target)
}
rangesOfNumber():获取字符串中数字的range数组
func rangesOfNumber() -> [NSRange] {
    return self.rangesOfRegex("[0-9]+")
}
pregReplace(pattern: String, with: String):使用正则表达式替换
func pregReplace(pattern: String, with: String,
                 options: NSRegularExpression.Options = []) -> String {
    let regex = try! NSRegularExpression(pattern: pattern, options: options)
    return regex.stringByReplacingMatches(in: self, options: [],
                                          range: NSMakeRange(0, self.count),
                                          withTemplate: with)
}
subRangeOfUrl():网址检查
func subRangeOfUrl() -> [NSRange] {
    let linkPattern = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\-.]+(?::(\\d+))?(?:(?:/[a-zA-Z0-9\\-._?,'+\\&%$=~*!():@\\\\]*)+)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)"
    guard let regex = try? NSRegularExpression(pattern: linkPattern, options: NSRegularExpression.Options.caseInsensitive) else {return []}
    let resultArr = regex.matches(in: self, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSRange(location: 0, length: (self as NSString).length))
    var rangeArr = [NSRange]()
    for item in resultArr {
        rangeArr.append(item.range)
    }
    return rangeArr
}
subscript (r: Range<Int>):String使用下标截取字符串,比如"示例字符串"[0..<2] 结果是 "示例"
subscript (r: Range<Int>) -> String {
    get {
        let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound)
        let endIndex = self.index(self.startIndex, offsetBy: r.upperBound)
        return String(self[startIndex..<endIndex])
    }
}
removeEmoji():移除emoji
func removeEmoji() -> String {
    let pattern = "[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]"
    return self.pregReplace(pattern: pattern, with: "")
}
字符串尺寸
heightForTextSize(fontSize: CGFloat, width: CGFloat):普通系统文本的高度
func heightForTextSize(fontSize: CGFloat, width: CGFloat) -> CGFloat {
    let font = UIFont.systemFont(ofSize: fontSize)
    return self.heightWithFont(font: font, width: width)
}
widthForTextSize(fontSize: CGFloat, height: CGFloat = 15):普通系统文本的高度
func widthForTextSize(fontSize: CGFloat, height: CGFloat = 15) -> CGFloat {
    let font = UIFont.systemFont(ofSize: fontSize)
    return self.widthWithFont(font: font,height: height)
}
heightWithBoldForTextSize(fontSize: CGFloat, width: CGFloat):加粗系统文本的高度
func heightWithBoldForTextSize(fontSize: CGFloat, width: CGFloat) -> CGFloat {
    let font = UIFont.boldSystemFont(ofSize: fontSize)
    return self.heightWithFont(font: font, width: width)
}
widthWithBoldForTextSize(fontSize: CGFloat, height: CGFloat = 15):加粗系统文本的宽度
func widthWithBoldForTextSize(fontSize: CGFloat, height: CGFloat = 15) -> CGFloat {
    let font = UIFont.boldSystemFont(ofSize: fontSize)
    return self.widthWithFont(font: font,height: height)
}
heightWithFont(font: UIFont, width: CGFloat):计算字体的高度
func heightWithFont(font: UIFont, width: CGFloat) -> CGFloat {
    let rect = NSString(string: self).boundingRect(with: CGSize(width: width, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
    return ceil(rect.height)
}
widthWithFont(font: UIFont, height: CGFloat = 15):计算字体的宽度
func widthWithFont(font: UIFont, height: CGFloat = 15) -> CGFloat {
    let rect = NSString(string: self).boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
    return ceil(rect.width)
}
boundingSize():计算字体尺寸
func boundingSize(withConstraintSize size: CGSize, font: UIFont, lineBreakMode: NSLineBreakMode = .byWordWrapping, option: NSStringDrawingOptions = .usesLineFragmentOrigin, context: NSStringDrawingContext? = nil) -> CGSize{
    return boundingRect(withSize: size, font: font, lineBreakMode: lineBreakMode, option: option, context: context).size
}
boundingRect():计算字体尺寸的实现方法
func boundingRect(withSize size: CGSize, font: UIFont, lineBreakMode: NSLineBreakMode = .byWordWrapping, option: NSStringDrawingOptions = .usesLineFragmentOrigin, context: NSStringDrawingContext? = nil) -> CGRect {
    let text = self as NSString
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineBreakMode = lineBreakMode;
    let attributes = [
        NSAttributedString.Key.font:font,
        NSAttributedString.Key.paragraphStyle:paragraphStyle
    ]
    return text.boundingRect(with: size, options: option, attributes: attributes, context: context)
}
字符串转对象
stringToDictionary():字符串转字典
func stringToDictionary() -> [String : Any]? {
    var result: [String : Any]?
    guard !self.isEmpty else { return result }
    guard let dataSelf = self.data(using: .utf8) else {
        return result
    }
    if let dic = (try? JSONSerialization.jsonObject(with: dataSelf, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String : Any] {
        result = dic
    }
    return result
}
stringToArray():字符串转数组
func stringToArray() -> [Any]? {
    var result: [Any]?
    guard !self.isEmpty else { return result }
    guard let dataSelf = self.data(using: .utf8) else {
        return result
    }
    if let array = (try? JSONSerialization.jsonObject(with: dataSelf, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [Any] {
        result = array
    }
    return result
}
toDouble():字符串转Double类型
func toDouble() -> Double {
    return Double(self) ?? 0
}
toFloat():字符串转Float类型
func toFloat() -> Float {
    return Float(toDouble())
}
toCGFloat():字符串转CGFloat类型
func toCGFloat() -> CGFloat {
    return CGFloat(toDouble())
}
toInt():字符串转Int类型
func toInt() -> Int {
    return Int(toDouble())
}
pinyinString():先转换为带音标的拼音,然后去掉音标
func pinyinString() -> String? {
    let mutableString = NSMutableString(string: self)
    if CFStringTransform(mutableString, nil, kCFStringTransformMandarinLatin, false) {
        if CFStringTransform(mutableString, nil, kCFStringTransformStripDiacritics, false) {
            return NSString(string: mutableString) as String
        }
    }
    return nil
}
firstChar():第一个字符
func firstChar() -> String {
    guard let first = self.trimmingCharacters(in: CharacterSet.whitespaces).first else {return ""}
    return "\(first)".uppercased()
}
返回NSAttributedString
setColor(subString: String,withColor color: UIColor,withFont font: UIFont):设置子字符串属性字体
func setColor(subString: String,withColor color: UIColor,withFont font: UIFont) -> NSMutableAttributedString {
    let tempNSString: NSString = self as NSString
    let range = tempNSString.range(of: subString)
    return self.setColor(range: range, withColor: color, withFont: font)
}
setColor(range: NSRange, withColor: UIColor, withFont: UIFont):设置某个范围内的属性字体
func setColor(range: NSRange, withColor: UIColor, withFont: UIFont) -> NSMutableAttributedString {
    let tempNSString: NSString = self as NSString
    let attributedString = NSMutableAttributedString(string: tempNSString as String)
    attributedString.addAttribute(NSAttributedString.Key.font, value: withFont, range: range)
    attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: withColor, range: range)
    return attributedString
}
attributedStringWithLineSpacing(lineSpacing: CGFloat):字符串配置文字行间距
func attributedStringWithLineSpacing(lineSpacing: CGFloat) -> NSMutableAttributedString {
    let attributedString = NSMutableAttributedString(string: self)
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.lineSpacing = lineSpacing
    attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, (self as NSString).length))
    return attributedString
}
字符串哈希值
filePathSha256():文件路径哈希值
func filePathSha256() -> String {
    let fileManager = FileManager.default
    if let url = URL.init(string: self) {
        if fileManager.fileExists(atPath: url.path) {
            let txtData = fileManager.contents(atPath: url.path)
            return hexStringFromData(input: digest(input: txtData! as NSData))
        }
    }
    return ""
}
hexStringFromData(input: NSData):从数据中获取到哈希字符串
private func hexStringFromData(input: NSData) -> String {
    var bytes = [UInt8](repeating: 0, count: input.length)
    input.getBytes(&bytes, length: input.length)

    var hexString = ""
    for byte in bytes {
        hexString += String(format:"%02x", UInt8(byte))
    }

    return hexString
}
digest(input : NSData):获取数据的SHA256加密
import CommonCrypto
private func digest(input : NSData) -> NSData {
    let digestLength = Int(CC_SHA256_DIGEST_LENGTH)
    var hash = [UInt8](repeating: 0, count: digestLength)
    CC_SHA256(input.bytes, UInt32(input.length), &hash)
    return NSData(bytes: hash, length: digestLength)
}

12、Timer 的扩展

public extension Timer
schedule(intervalFromNow: TimeInterval, block: @escaping () -> ()):只执行一次的计时器
@discardableResult
class func schedule(intervalFromNow: TimeInterval, block: @escaping () -> ()) -> Timer {
    let actor = TimerActor(block: block)
    let timer = Timer.init(timeInterval: intervalFromNow, target: actor, selector: #selector(actor.fire), userInfo: nil, repeats: false)
    RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
    return timer
}
schedule(every interval: TimeInterval, block: @escaping () -> ()):重复执行的计时器
@discardableResult
class func schedule(every interval: TimeInterval, block: @escaping () -> ()) -> Timer {
    let actor = TimerActor(block: block)
    let timer = Timer.init(timeInterval: interval, target: actor, selector: #selector(fire), userInfo: nil, repeats: true)
    RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
    return timer
}
TimerActor:计时器的中介者对象
private class TimerActor {
    var block: () -> ()
    
    init(block: @escaping () -> ()) {
        self.block = block
    }
    
    @objc dynamic func fire() {
        block()
    }
}
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容