为啥我的代码可以在 Xcode Playground 中运行,但不能在我的项目中运行?
Posted
技术标签:
【中文标题】为啥我的代码可以在 Xcode Playground 中运行,但不能在我的项目中运行?【英文标题】:Why does my code work in Xcode Playground but not in my project?为什么我的代码可以在 Xcode Playground 中运行,但不能在我的项目中运行? 【发布时间】:2020-05-29 14:58:04 【问题描述】:我正在尝试解析 Calibre 用于通过 Swift 管理电子书的 metadata.opf 文件。
我设法在操场上解析文档:
import Foundation
class Metadata: CustomStringConvertible
var uuid = ""
var title = ""
var creators = [""]
var serie = ""
var serieIndex = 0
var description: String return
"UUID: \(uuid)\nTitre: \(title)\nAuteur(s): \(creators)\nSérie: Tome \(serieIndex) de la série \(serie)"
class OPFParser: NSObject
var xmlParser: XMLParser?
var metadata: [Metadata] = []
var xmlText = ""
var currentMetadata: Metadata?
var calibreAttributes: [String: String] = [:]
var isUUID = false
init(withXML xml: String)
if let data = xml.data(using: .utf8)
xmlParser = XMLParser(data: data)
func parse() -> [Metadata]
xmlParser?.delegate = self
xmlParser?.parse()
return metadata
extension OPFParser: XMLParserDelegate
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:])
xmlText = ""
if elementName == "metadata"
currentMetadata = Metadata()
if elementName == "meta"
//print("\(attributeDict["content"]) : \(attributeDict["name"])")
if attributeDict["name"] == "calibre:series"
if let serie = attributeDict["content"]
currentMetadata?.serie = serie
if attributeDict["name"] == "calibre:series_index"
if let serieIndex = attributeDict["content"]
currentMetadata?.serieIndex = Int(serieIndex) ?? 0
if elementName == "dc:identifier"
if let uuuid = attributeDict["opf:scheme"]
if uuuid == "uuid"
isUUID = true
else isUUID = false
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
switch elementName
case "dc:identifier":
if isUUID == true
currentMetadata?.uuid = xmlText.trimmingCharacters(in: .whitespacesAndNewlines)
case "dc:title":
currentMetadata?.title = xmlText.trimmingCharacters(in: .whitespacesAndNewlines)
case "dc:creator":
currentMetadata?.creators.append(xmlText.trimmingCharacters(in: .whitespacesAndNewlines))
case "metadata":
if let meta = currentMetadata
metadata.append(meta)
default:
break
func parser(_ parser: XMLParser, foundCharacters string: String)
xmlText += string
class TestMetadata
func metadataDisplay()
if let xmlUrl = Bundle.main.url(forResource: "metadata1", withExtension: "opf")
let xml = try! String(contentsOf: xmlUrl)
let opfParser = OPFParser(withXML: xml)
let bandeDessinees = opfParser.parse()
for bandeDessinee in bandeDessinees
bandeDessinee.creators = bandeDessinee.creators.filter( $0 != "")
print(bandeDessinee)
else print("fichier non trouvé")
let testMetadata = TestMetadata()
testMetadata.metadataDisplay()
metadataDisplay 函数起作用,并打印格式化的元数据。不幸的是,当切换到我的项目时,metadataDisplay 不打印任何内容。 bandedessinees
数组为空。我使用的是相同的代码,只是我从 swiftUI 文件中的按钮调用 metadataDisplay。我尝试多次重构代码,修改了'init()function of my
OPFParser`类,但不幸的是我无法弄清楚为什么我的元数据没有打印在控制台中。
感谢您的帮助, 艾曼。
示例 metadata.opf 文件:
<?xml version='1.0' encoding='utf-8'?>
<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="uuid_id" version="2.0">
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
<dc:identifier opf:scheme="calibre" id="calibre_id">143</dc:identifier>
<dc:identifier opf:scheme="uuid" id="uuid_id">03badde9-0932-41ab-bd31-2dbba989a7f5</dc:identifier>
<dc:title>Tome 1</dc:title>
<dc:creator opf:file-as="Debeurme, Ludovic" opf:role="aut">Ludovic Debeurme</dc:creator>
<dc:contributor opf:file-as="calibre" opf:role="bkp">calibre (4.15.0) [https://calibre-ebook.com]</dc:contributor>
<dc:date>2018-05-20T16:16:27+00:00</dc:date>
<dc:language>en</dc:language>
<meta content=""Ludovic Debeurme": """ name="calibre:author_link_map"/>
<meta content="Epiphania" name="calibre:series"/>
<meta content="1" name="calibre:series_index"/>
<meta content="2020-05-16T13:01:05.580464+00:00" name="calibre:timestamp"/>
<meta content="Tome 1" name="calibre:title_sort"/>
<meta name="calibre:user_metadata:#shelves" content=""table": "custom_column_1", "is_editable": true, "is_custom": true, "rec_index": 22, "is_category": true, "is_multiple2": "ui_to_list": ",", "list_to_ui": ", ", "cache_to_list": "|", "name": "Shelves", "is_multiple": "|", "is_csp": false, "category_sort": "value", "#extra#": null, "kind": "field", "#value#": [], "display": "is_names": false, "description": "", "search_terms": ["#shelves"], "datatype": "text", "colnum": 1, "label": "shelves", "link_column": "value", "column": "value""/>
</metadata>
<guide>
<reference href="cover.jpg" title="Cover" type="cover"/>
</guide>
</package>
【问题讨论】:
您是否设置了断点并在调试中单步执行以查看发生了什么?xml
的值是多少?旁注:您应该将let xml = try String(contentsOf: xmlUrl)
包装在do catch
块中以确保String(contentsOf: xmlUrl)
成功。
我在 SwiftUI 视图中尝试了您的代码,没有遇到任何问题。
@DonMag 我已经使用打印语句来尝试查找问题,并为 xml 找到了一个值。感谢您的 do/catch 建议,我会将其添加到我的函数中!
@Frankenstein 感谢您的反馈,我会换一个视图试试。
@AymaneBengrina - 你能发布一个示例文件看看我们是否可以复制这个问题吗?
【参考方案1】:
我终于弄对了,问题出在 XML 文件的编码上。通过从XMLParser(data: Data)
切换到XMLParser(contentsOf: URL)
,解析器返回一个非空数组。
【讨论】:
以上是关于为啥我的代码可以在 Xcode Playground 中运行,但不能在我的项目中运行?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Xcode 将我的所有代码编译两次,导致任何全局变量的链接器错误?