本章内容概览:Swift内置基础库(时间、格式化、度量值、Data、文件、Scanner、AttributeString、随机、UserDefaults)
上一节:【iOS】04_Swift基础语法(操作符)
下一节:【iOS】06_系统及设备
同系列文章请查看:快乐码元 - iOS篇
1.时间
1.1 Date 的基本用法
Date 转 时间戳:
1 2 3 4 let interval = now.timeIntervalSince1970 let df = DateFormatter ()df.dateFormat = "yyyy 年 MM 月 dd 日 HH:mm:ss" print ("时间戳:\(Int(interval)) " )
格式化的时间:
1 print ("格式化的时间:" + df.string(from: now))
short 样式时间:
1 2 df.dateStyle = .short print ("short 样式时间:" + df.string(from: now))
full 样式时间:
1 2 3 df.locale = Locale (identifier: "zh_Hans_CN" ) df.dateStyle = .full print ("full 样式时间:" + df.string(from: now))
时间戳转 Date:
1 2 let date = Date (timeIntervalSince1970: interval)print (date)
1.2 复杂的时间操作
比如说 GitHub 接口使用的是 ISO 标准,RSS 输出的是 RSS 标准字符串,不同标准对应不同时区的时间计算处理,可以使用开源库 SwiftDate 来完成。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import SwiftDatelet cn = Region (zone: Zones .asiaShanghai, locale: Locales .chineseChina)SwiftDate .defaultRegion = cnprint ("2008-02-14 23:12:14" .toDate()? .year ?? "" ) let d1 = "2022-01-17T23:20:35" .toISODate(region: cn)guard let d1 = d1 else { return } print (d1.minute) let d2 = d1 + 1 .minutesprint (d2.minute)let i1 = DateInRegion (Date (), region: cn) - d1let s1 = i1.toString { $0 .maximumUnitCount = 4 $0 .allowedUnits = [.day, .hour, .minute] $0 .collapsesLargestUnit = true $0 .unitsStyle = .abbreviated $0 .locale = Locales .chineseChina } print (s1)
2.格式化 - 描述
使用标准库的格式来描述不同场景的情况可以不用去考虑由于不同地区的区别,这些在标准库里就可以自动完成了。
2.1 描述两个时间之间相差多长时间
计算两个时间之间相差多少时间 ,支持多种语言字符串:
1 2 3 4 5 6 7 let d1 = Date ().timeIntervalSince1970 - 60 * 60 * 24 let f1 = RelativeDateTimeFormatter ()f1.dateTimeStyle = .named f1.formattingContext = .beginningOfSentence f1.locale = Locale (identifier: "zh_Hans_CN" ) let str = f1.localizedString(for: Date (timeIntervalSince1970: d1), relativeTo: Date ())print (str)
简写:
1 2 3 let str2 = Date .now.addingTimeInterval(- (60 * 60 * 24 )) .formatted(.relative(presentation: .named)) print (str2)
描述多个事物 :
1 2 3 let s1 = ListFormatter .localizedString(byJoining: ["冬天" ,"春天" ,"夏天" ,"秋天" ])print (s1)
描述名字 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 let f2 = PersonNameComponentsFormatter ()var nc1 = PersonNameComponents ()nc1.familyName = "宋" nc1.givenName = "潇" nc1.nickname = "宋宋" print (f2.string(from: nc1)) f2.style = .short print (f2.string(from: nc1)) f2.style = .abbreviated print (f2.string(from: nc1)) var nc2 = PersonNameComponents ()nc2.familyName = "Song" nc2.givenName = "Xiao" nc2.nickname = "SongSong" f2.style = .default print (f2.string(from: nc2)) f2.style = .short print (f2.string(from: nc2)) f2.style = .abbreviated print (f2.string(from: nc2)) let componets = f2.personNameComponents(from: "宋潇" )print (componets? .givenName ?? "" )
描述数字 :
1 2 3 4 5 6 7 8 9 10 11 let f3 = NumberFormatter ()f3.locale = Locale (identifier: "zh_Hans_CN" ) f3.numberStyle = .currency print (f3.string(from: 123456 ) ?? "" ) f3.numberStyle = .percent print (f3.string(from: 123456 ) ?? "" ) let n1 = 1.23456 let n1Str = n1.formatted(.number.precision(.fractionLength(3 )).rounded())print (n1Str)
描述地址 :
1 2 3 4 5 6 7 8 9 10 11 12 13 import Contactslet f4 = CNPostalAddressFormatter ()let address = CNMutablePostalAddress ()address.street = "海淀区王庄路XX号院X号楼X门XXX" address.postalCode = "100083" address.city = "北京" address.country = "中国" print (f4.string(from: address))
3.度量值
标准库里的物理量,在这个文档里有详细列出,包括角度、平方米等。
参考:https://developer.apple.com/documentation/foundation/nsdimension
1 2 3 4 5 6 7 let m1 = Measurement (value: 1 , unit: UnitLength .kilometers)let m2 = m1.converted(to: .meters) print (m2) let mf = MeasurementFormatter ()mf.locale = Locale (identifier: "zh_Hans_CN" ) print (mf.string(from: m1))
一些物理公式供参考:
1 2 3 4 5 6 7 8 9 10 11 12 13 面积 = 长度 × 长度 体积 = 长度 × 长度 × 长度 = 面积 × 长度 速度=长度/时间 加速度=速度/时间 力 = 质量 × 加速度 扭矩 = 力 × 长度 压力 = 力 / 面积 密度=质量 / 体积 能量 = 功率 × 时间 电阻 = 电压 / 电流
3.Data
数据压缩和解压
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let d1 = "看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?看看能够压缩多少?" .data(using: .utf8)! as NSData print ("ori \(d1.count) bytes" )do { let compressed = try d1.compressed(using: .zlib) print ("comp \(compressed.count) bytes" ) let decomressed = try compressed.decompressed(using: .zlib) let deStr = String (data: decomressed as Data , encoding: .utf8) print (deStr ?? "" ) } catch {}
4.文件
4.1 文件的一些基本操作
1 2 let path1 = "/Users/mingdai/Downloads/1.html" let path2 = "/Users/mingdai/Documents/GitHub/"
1 2 3 4 5 6 7 8 9 10 11 let u1 = URL (string: path1)do { let url1 = try FileManager .default.url(for: .itemReplacementDirectory, in: .userDomainMask, appropriateFor: u1, create: true ) print (url1) let s1 = try String (contentsOfFile: path1, encoding: .utf8) print (s1) } catch {}
1 2 3 4 5 6 7 8 9 10 11 12 let u2 = URL (fileURLWithPath:path2)do { let values = try u2.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey]) if let capacity = values.volumeAvailableCapacityForImportantUsage { print ("可用: \(capacity) " ) } else { print ("不可用" ) } } catch { print ("错误: \(error.localizedDescription) " ) }
4.2 遍历多级目录结构中的文件
怎么遍历多级目录结构中的文件呢?看下面的代码的实现:
1 2 3 4 5 6 7 8 9 10 let u3 = URL (fileURLWithPath: FileManager .default.currentDirectoryPath)let fm = FileManager .defaultfm.enumerator(atPath: u3.path)? .forEach({ path in guard let path = path as? String else { return } let url = URL (fileURLWithPath: path, relativeTo: u3) print (url.lastPathComponent) })
4.3 创建文件夹和文件
可以使用 FileWrapper 来创建文件夹和文件。举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 let f1 = FileWrapper (regularFileWithContents: Data ("# 第 n 个文件\n ## 标题" .utf8))f1.fileAttributes[FileAttributeKey .creationDate.rawValue] = Date () f1.fileAttributes[FileAttributeKey .modificationDate.rawValue] = Date () let folder1 = FileWrapper (directoryWithFileWrappers: [ "file1.md" : f1 ]) folder1.fileAttributes[FileAttributeKey .creationDate.rawValue] = Date () folder1.fileAttributes[FileAttributeKey .modificationDate.rawValue] = Date () do { try folder1.write( to: URL (fileURLWithPath: FileManager .default.currentDirectoryPath).appendingPathComponent("NewFolder" ), options: .atomic, originalContentsURL: nil ) } catch {} print (FileManager .default.currentDirectoryPath)
上面代码写起来比较繁琐,对 FileWrapper 更好的封装可以参考这篇文章《 A Type-Safe FileWrapper | Heberti Almeida 》。
文件读写处理完整能力可以参看这个库 GitHub - JohnSundell/Files: A nicer way to handle files & folders in Swift
本地或者网络上,比如网盘和FTP的文件发生变化时,怎样知道能够观察到呢?
通过 HTTPHeader 里的 If-Modified-Since、Last-Modified、If-None-Match 和 Etag 等字段来判断文件的变化,本地则是使用 DispatchSource.makeFileSystemObjectSource 来进行的文件变化监听。可以参考 KZFileWatchers 库的做法。
5.Scanner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 let s1 = """ one1, two2, three3. """ let sn1 = Scanner (string: s1)while ! sn1.isAtEnd { if let r1 = sn1.scanUpToCharacters(from: .newlines) { print (r1 as String ) } } let sn2 = Scanner (string: s1)sn2.charactersToBeSkipped = CharacterSet .decimalDigits.inverted var p: Int = 0 while ! sn2.isAtEnd { if sn2.scanInt(& p) { print (p) } }
上面的代码还不是那么 Swifty,可以通过用AnySequence和AnyIterator来包装下,将序列中的元素推迟到实际需要时再来处理,这样性能也会更好些。具体实现可以参看《 String parsing in Swift 》这篇文章。
6.AttributeString
效果如下:
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 var aStrs = [AttributedString ]()var aStr1 = AttributedString (""" 标题 正文内容,具体查看链接。 这里摘出第一个重点,还要强调的内容。 """ )let title = aStr1.range(of: "标题" )guard let title = title else { return aStrs } var c1 = AttributeContainer () c1.inlinePresentationIntent = .stronglyEmphasized c1.font = .largeTitle aStr1[title].setAttributes(c1) let link = aStr1.range(of: "链接" )guard let link = link else { return aStrs } var c2 = AttributeContainer () c2.strokeColor = .blue c2.link = URL (string: "https://ming1016.github.io/" ) aStr1[link].setAttributes(c2.merging(c1)) let i1 = aStr1.range(of: "重点" )let i2 = aStr1.range(of: "强调" )guard let i1 = i1, let i2 = i2 else { return aStrs } var c3 = AttributeContainer ()c3.foregroundColor = .yellow c3.inlinePresentationIntent = .stronglyEmphasized aStr1[i1].setAttributes(c3) aStr1[i2].setAttributes(c3) for r in aStr1.runs { print ("-------------" ) print (r.attributes) } aStrs.append(aStr1) do { let aStr2 = try AttributedString (markdown: """ 内容[链接](https://ming1016.github.io/)。需要**强调**的内容。 """ ) aStrs.append(aStr2) } catch {}
SwiftUI 的 Text 可以直接读取 AttributedString 来进行显示。
7.随机
用法:
1 2 3 4 5 let ri = Int .random(in: 0 ..< 10 )print (ri) let a = [0 , 1 , 2 , 3 , 4 , 5 ]print (a.randomElement() ?? 0 ) print (a.shuffled())
8.UserDefaults
使用方法如下:
1 2 3 4 5 6 7 enum UDKey { static let k1 = "token" } let ud = UserDefaults .standardud.set("xxxxxx" , forKey: UDKey .k1) let tk = ud.string(forKey: UDKey .k1)print (tk ?? "" )
参考资料:
Tips:
Please indicate the source and original author when reprinting or quoting this article.