iOS开发中的文档处理与数据解析
1. 自定义文档缩略图
在iOS开发中,有时候需要为自定义文档提供缩略图。以下是实现自定义文档缩略图的代码:
override func provideThumbnail(for request: QLFileThumbnailRequest,
_ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {
let furl = request.fileURL
let name = furl.deletingPathExtension().lastPathComponent
let im = UIImage(named:"smiley.jpg")!
let maxsz = request.maximumSize
let r = AVMakeRect(aspectRatio: im.size,
insideRect: CGRect(origin:.zero, size:maxsz))
let att = NSAttributedString(string:name, attributes:[
.font:UIFont(name:"Georgia", size:14)!
])
let attsz = att.size()
func draw() -> Bool {
im.draw(in: CGRect(origin:.zero, size:r.size))
att.draw(at: CGPoint(
(r.width - attsz.width)/2,
(r.height - attsz.height)/2))
return true
}
let reply = QLThumbnailReply(
contextSize: r.size, currentContextDrawing: draw)
handler(reply, nil)
}
上述代码的执行流程如下:
1. 从请求中获取文件URL和文件名。
2. 加载指定的图片作为缩略图的基础图像。
3. 根据请求的最大尺寸,计算图像的显示区域。
4. 创建包含文件名的属性字符串。
5. 定义绘制函数,将图像和文件名绘制到指定区域。
6. 创建
QLThumbnailReply
对象,并调用处理程序返回结果。
2. 自定义文档预览
当用户收到自定义的People Group文档并尝试在邮件应用中预览时,默认情况下可能无法正常预览。为了解决这个问题,可以为People Groups应用添加Quick Look预览扩展。
操作步骤如下:
1.
添加目标
:选择iOS → Application Extension → Quick Look Preview Extension。模板会提供一个视图控制器类
PreviewViewController
和一个包含该实例及其主视图的故事板。
2.
配置Info.plist
:在
QLSupportedContentTypes
数组中声明要提供预览的文档类型的UTI,并关闭
QLSupportsSearchableItems
设置。
3.
实现
preparePreviewOfFile(at:completionHandler:)
方法
:
func preparePreviewOfFile(at url: URL,
completionHandler handler: @escaping (Error?) -> Void) {
let doc = PeopleDocument(fileURL:url)
doc.open { ok in
if ok {
self.people = doc.people
self.tableView.register(
UINib(nibName: "PersonCell", bundle: nil),
forCellReuseIdentifier: "Person")
self.tableView.reloadData()
handler(nil)
} else {
handler(NSError(domain: "NoDataDomain",
code: -1, userInfo: nil))
}
}
}
该方法的执行流程如下:
1. 根据文件URL创建
PeopleDocument
对象。
2. 打开文档,如果成功则将文档中的人员数据赋值给视图控制器的
people
属性。
3. 注册表格视图的单元格。
4. 重新加载表格视图数据。
5. 调用完成处理程序,若成功则传入
nil
,若失败则传入错误对象。
3. 文档选择器
文档选择器(
UIDocumentPickerViewController
)是一种让用户查看文档列表并选择一个或多个文件的简单方式。可以直接打开文件,也可以将其临时复制到应用的沙盒中。
以下是一个允许用户选择
.mp3
文件并播放的示例:
@IBAction func doButton(_ sender: Any) {
let picker = UIDocumentPickerViewController(
documentTypes: [kUTTypeMP3 as String], in: .import)
picker.delegate = self
self.present(picker, animated: true)
}
func documentPicker(_ controller: UIDocumentPickerViewController,
didPickDocumentsAt urls: [URL]) {
guard urls.count == 1 else {return}
guard let vals =
try? urls[0].resourceValues(forKeys: [.typeIdentifierKey]),
vals.typeIdentifier == kUTTypeMP3 as String
else {return}
let vc = AVPlayerViewController()
vc.player = AVPlayer(url: urls[0])
self.present(vc, animated: true)
}
操作步骤如下:
1.
创建文档选择器
:指定要选择的文件类型为
.mp3
,并设置选择模式为导入。
2.
设置代理并呈现选择器
:将当前视图控制器设置为选择器的代理,并呈现选择器。
3.
处理文件选择结果
:在代理方法中,检查选择的文件是否为
.mp3
文件,若是则创建
AVPlayerViewController
并播放该文件。
4. XML解析
XML是一种灵活且广泛使用的通用文本文件格式,用于存储和检索结构化数据。在iOS中,使用
XMLParser
来解析XML数据。
以下是一个简单的XML示例:
<?xml version="1.0" encoding="utf-8"?>
<people>
<person>
<firstName>Matt</firstName>
<lastName>Neuburg</lastName>
</person>
<person>
<firstName>Snidely</firstName>
<lastName>Whiplash</lastName>
</person>
<person>
<firstName>Dudley</firstName>
<lastName>Doright</lastName>
</person>
</people>
使用
XMLParser
解析XML的步骤如下:
1.
创建
XMLParser
对象
:传入本地XML文件的URL或从网络下载的
Data
对象。
2.
设置代理
:实现代理方法来处理解析过程中的事件。
3.
开始解析
:调用
parse()
方法开始解析。
对于简单的XML,有三个重要的代理方法:
-
parser(_:didStartElement:namespaceURI:qualifiedName:attributes:)
:遇到开始元素标签时调用。
-
parser(_:didEndElement:namespaceURI:qualifiedName:)
:遇到结束元素标签时调用。
-
parser(_:foundCharacters:)
:遇到元素标签之间的文本时调用。
为了更好地处理解析过程中的状态维护问题,可以在不同的解析阶段重置
XMLParser
的代理。例如,使用
PeopleParser
处理
<people>
元素,使用
PersonParser
处理
<person>
元素。
graph LR
A[创建XMLParser] --> B[设置代理为PeopleParser]
B --> C[开始解析]
C --> D{遇到<person>元素}
D -- 是 --> E[创建PersonParser并设置为代理]
E --> F[PersonParser处理<person>元素]
F --> G{解析结束}
G -- 是 --> H[恢复PeopleParser为代理]
D -- 否 --> I[PeopleParser继续处理]
5. JSON解析
JSON是一种常用的轻量级结构化数据格式,用于服务器通信。以下是一个请求服务器获取随机设计名言的示例:
let sess : URLSession = {
let config = URLSessionConfiguration.ephemeral
let s = URLSession(configuration: config)
return s
}()
@IBAction func doGo(_ sender: Any) {
var comp = URLComponents()
comp.scheme = "https"
comp.host = "quotesondesign.com"
comp.path = "/wp-json/posts"
var qi = [URLQueryItem]()
qi.append(URLQueryItem(name: "filter[orderby]", value: "rand"))
qi.append(URLQueryItem(name: "filter[posts_per_page]", value: "1"))
comp.queryItems = qi
if let url = comp.url {
let d = self.sess.dataTask(with: url) { data,_,_ in
if let data = data {
DispatchQueue.main.async {
self.parse(data)
}
}
}
d.resume()
}
}
服务器返回的JSON数据可能如下:
[
{
"ID":950,
"title":"Joan Miro",
"content":"<p>The works must be conceived with fire in the soul, but executed with clinical coolness. </p>n",
"link":"https://quotesondesign.com/joan-miro/"
}
]
解析JSON的步骤如下:
1. 定义与JSON格式匹配的结构体,并采用
Decodable
协议。
struct Quote : Decodable {
let title : String
let content : String
}
-
创建
JSONDecoder对象并调用decode(_:from:)方法进行解析。
func parse(_ data:Data) {
if let arr = try? JSONDecoder().decode([Quote].self, from: data) {
let quote = arr.first!
// ...
}
}
当JSON结构较为复杂时,可能需要自定义
init(from:)
方法。例如,处理包含可变键名的JSON数据:
[
{
"categoryName": "Trending",
"Trending": [
{
"category": "Trending",
"price": 20.5,
"isFavourite": true,
"isWatchlist": null
}
]
},
{
"categoryName": "Comedy",
"Comedy": [
{
"category": "Comedy",
"price": 24.32,
"isFavourite": null,
"isWatchlist": false
}
]
}
]
需要定义
Inner
结构体处理内部字典,定义
Outer
结构体处理外部字典,并实现自定义的
init(from:)
方法。
struct Inner : Decodable {
let category : String
let price : Double
let isFavourite : Bool?
let isWatchlist : Bool?
}
struct Outer : Decodable {
let categoryName : String
let unknown : [Inner]
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: CK.self)
self.categoryName = try! con.decode(
String.self, forKey:CK(stringValue:"categoryName")!)
self.unknown = try! con.decode(
[Inner].self, forKey: CK(stringValue:self.categoryName)!)
}
}
struct CK : CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
最后,使用
JSONDecoder
解析JSON数据:
if let myjson = try? JSONDecoder().decode([Outer].self, from: data) {
// ...
}
通过以上介绍,我们了解了iOS开发中自定义文档缩略图、预览、选择,以及XML和JSON数据解析的相关知识和实现方法。这些技术在实际开发中非常有用,可以帮助我们更好地处理文档和数据。
iOS开发中的文档处理与数据解析(续)
6. 数据解析总结
在iOS开发中,XML和JSON是两种常见的数据格式,它们在存储和传输结构化数据方面各有优势。下面对它们的解析方法进行一个对比总结:
| 数据格式 | 解析方式 | 特点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| XML | 使用
XMLParser
,在解析过程中通过代理方法处理不同元素和文本 | 需要手动维护解析状态,适合处理结构层次分明、元素关系复杂的数据 | 配置文件、数据交换 |
| JSON | 使用
JSONDecoder
,结合
Decodable
协议,可自动解析符合结构体定义的数据 | 解析简单,代码量少,适合处理轻量级、结构相对固定的数据 | 网络数据传输、服务器通信 |
7. 文档处理和数据解析的综合应用
在实际的iOS应用开发中,文档处理和数据解析往往是结合使用的。例如,一个音乐播放应用可能会使用文档选择器让用户选择音乐文件,同时使用JSON解析从服务器获取音乐的相关信息,如歌曲名称、歌手、专辑封面等。
以下是一个简单的综合应用示例,假设应用中有一个按钮,点击按钮后用户可以选择一个音乐文件,并从服务器获取该音乐的相关信息:
import UIKit
import AVKit
import Foundation
class ViewController: UIViewController, UIDocumentPickerDelegate {
let sess : URLSession = {
let config = URLSessionConfiguration.ephemeral
let s = URLSession(configuration: config)
return s
}()
@IBAction func doAction(_ sender: Any) {
// 打开文档选择器
let picker = UIDocumentPickerViewController(documentTypes: [kUTTypeMP3 as String], in: .import)
picker.delegate = self
self.present(picker, animated: true)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard urls.count == 1 else { return }
guard let vals = try? urls[0].resourceValues(forKeys: [.typeIdentifierKey]),
vals.typeIdentifier == kUTTypeMP3 as String else { return }
// 播放音乐
let vc = AVPlayerViewController()
vc.player = AVPlayer(url: urls[0])
self.present(vc, animated: true)
// 获取音乐相关信息
var comp = URLComponents()
comp.scheme = "https"
comp.host = "musicapi.example.com"
comp.path = "/api/music/info"
var qi = [URLQueryItem]()
qi.append(URLQueryItem(name: "filename", value: urls[0].lastPathComponent))
comp.queryItems = qi
if let url = comp.url {
let d = self.sess.dataTask(with: url) { [weak self] data, _, _ in
if let data = data {
DispatchQueue.main.async {
self?.parseMusicInfo(data)
}
}
}
d.resume()
}
}
func parseMusicInfo(_ data: Data) {
struct MusicInfo: Decodable {
let title: String
let artist: String
let albumCover: String
}
if let musicInfo = try? JSONDecoder().decode(MusicInfo.self, from: data) {
// 处理音乐信息,如显示在界面上
print("Title: \(musicInfo.title), Artist: \(musicInfo.artist), Album Cover: \(musicInfo.albumCover)")
}
}
}
上述代码的执行流程如下:
1. 用户点击按钮,触发
doAction
方法,打开文档选择器。
2. 用户选择一个
.mp3
音乐文件后,
documentPicker
方法被调用,播放该音乐文件。
3. 同时,向服务器发送请求,获取该音乐的相关信息。
4. 服务器返回JSON格式的音乐信息,调用
parseMusicInfo
方法进行解析。
5. 解析成功后,将音乐信息打印输出,也可以将其显示在界面上。
8. 注意事项和优化建议
在进行文档处理和数据解析时,有一些注意事项和优化建议:
-
内存管理
:在处理大文件或大量数据时,要注意内存的使用情况。例如,在解析XML时,如果数据量过大,可能会导致内存占用过高。可以考虑分块解析或使用更高效的数据结构。
-
错误处理
:在文档处理和数据解析过程中,可能会出现各种错误,如文件不存在、网络请求失败、数据格式错误等。要对这些错误进行适当的处理,给用户友好的提示。
-
性能优化
:对于JSON解析,可以通过合理设计结构体和使用
CodingKeys
枚举来提高解析效率。对于XML解析,可以使用状态机或代理模式来简化代码和提高性能。
9. 未来发展趋势
随着移动应用的不断发展,文档处理和数据解析技术也在不断进步。未来,可能会出现更高效、更智能的解析方法和工具。例如,自动识别数据格式并进行解析,或者使用机器学习技术对数据进行预处理和分析。
同时,随着云存储和云计算的普及,文档处理和数据解析将更多地与云端服务结合,实现数据的实时同步和共享。开发者需要不断学习和掌握新的技术,以适应未来的发展需求。
通过对iOS开发中文档处理和数据解析的深入学习和实践,开发者可以更好地开发出功能强大、用户体验良好的应用程序。无论是处理自定义文档,还是解析XML和JSON数据,都需要根据具体的需求选择合适的方法和工具,并注意性能和错误处理等方面的问题。希望本文能为iOS开发者在文档处理和数据解析方面提供一些有用的参考。
超级会员免费看
2105

被折叠的 条评论
为什么被折叠?



