Post

Replies

Boosts

Views

Activity

Reply to Cannot preview in this file- *app crashed
Could you please provide the code in which you’re previewing from? Even if the compiler sees no issue, there could still be an error that makes the app malfunction. Also, did you add any code that made it stop working? What was the difference from the working code versus the non-working code?
Mar ’21
Reply to (Expansion) Retrieve articles from an XML parser
extension ArticlesInfo { var dataUrl: URL { FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] .appendingPathComponent("THS.xml") } func saveArticles() { do { //Convert Array of `CardInfo` to `Data` let data = try JSONEncoder().encode(dataUrl) //Write `Data` to a file specified by URL try data.write(to: dataUrl, options: .atomic) } catch { print(error) } } func loadArticles() { do { if FileManager.default.fileExists(atPath: dataUrl.path) { return } //Read `Data` from a file specified by URL let data = try Data(contentsOf: dataUrl) //Parse Available Articles let articles = try JSONDecoder().decode([ArticleInfo].self, from: data) self.articles = articles } catch { print(error) } } } The code that was here was moved into ArticlesInfo itself and eventually changed into what it is now.
Mar ’21
Reply to (Expansion) Retrieve articles from an XML parser
Here's code for ArticleInfo since it was updated to integrate the extension into the actual ObservableObject: import Foundation struct ArticleInfo: Identifiable, Codable {     var id: String = ""     var title: String = ""     var date: Date?     var author: String = ""     var img: URL?     var content: String = "" } class ArticlesInfo: ObservableObject {     @Published var articles: [ArticleInfo] = []     var dataUrl = URL(string: "https://storage.googleapis.com/thehairsociety/2021/03/2f23e2d4-ths.xml")          func loadArticles() {         do {             let data = try Data(contentsOf: dataUrl!)             let parser = ArticlesParser(data: data)             if parser.parse() {                 print(parser.articles) // Value of type 'ArticlesParser' has no property 'articles'                 let articles: try //...?                 self.articles = articles // Unsure what I put here             } else {                 if let error = parser.parserError {                     print(error)                 } else {                     print("Failed with unknown reason")                 }             }         } catch {             print(error)         }     } } class ArticlesParser: XMLParser {     var dateTimeZone = TimeZone(abbreviation: "GMT-6")     lazy var dateFormater: DateFormatter = {         let df = DateFormatter()         df.locale = Locale(identifier: "en_US_POSIX")         df.dateFormat = "MMM dd, yyyy"         df.timeZone = dateTimeZone         return df     }()          private var textBuffer: String = ""     private var nextArticle: ArticleInfo? = nil     override init(data: Data) {         super.init(data: data)         self.delegate = self     } } extension ArticlesParser: XMLParserDelegate {     // Called when opening tag (`elementName`) is found     func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {         switch elementName {         case "posts":             nextArticle = ArticleInfo()         case "title":             textBuffer = ""         case "date":             textBuffer = ""         case "author":             textBuffer = ""         case "img":             textBuffer = ""         case "content":             textBuffer = ""         default:             print("Ignoring \(elementName)")             break         }     }          // Called when closing tag (`/elementName`) is found     func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {         switch elementName {         case "posts":             if let article = nextArticle {                 articles.append(article) // Cannot find 'articles' in scope             }         case "title":             nextArticle?.title = textBuffer         case "date":             print("date: \(textBuffer)")             nextArticle?.date = dateFormater.date(from: textBuffer)         case "author":             nextArticle?.author = textBuffer         case "img":             print("img: \(textBuffer)")             nextArticle?.img = URL(string: textBuffer)         case "content":             nextArticle?.content = textBuffer         default:             print("Ignoring \(elementName)")             break         }     }          // Called when a character sequence is found     // This may be called multiple times in a single element     func parser(_ parser: XMLParser, foundCharacters string: String) {         textBuffer += string     }          // Called when a CDATA block is found     func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {         guard let string = String(data: CDATABlock, encoding: .utf8) else {             print("CDATA contains non-textual data, ignored")             return         }         textBuffer += string     }          // For debugging     func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {         print(parseError)         print("on:", parser.lineNumber, "at:", parser.columnNumber)     } }
Mar ’21
Reply to (Expansion) Retrieve articles from an XML parser
Why did you remove articles? I completely do not understand why. I don't understand how I removed articles. Sorry if I'm missing something but I don't remember ever removing it. It's in the ObservableObject where you told me to put it in the first place. You can do it in the same way: class ArticlesInfo: ObservableObject { @Published var articles: ... //... func loadArticles() { // Use `ArticlesParser` here //... } }
Mar ’21
Reply to (Expansion) Retrieve articles from an XML parser
Sorry, I do not understand why you removed it. It is I who is confused. Apologies, I must have switched it around. ArticlesParser now holds articles as a published variable. But ArticlesInfo - where the loadArticles() function is held - now cannot call articles because that property does not exist in ArticlesInfo. class ArticlesInfo: ObservableObject {     var dataUrl = URL(string: https://storage.googleapis.com/thehairsociety/2021/03/2f23e2d4-ths.xml)     func loadArticles() {         do {             if FileManager.default.fileExists(atPath: dataUrl!.path) {                 return             }             //Read `Data` from a file specified by URL             let data = try Data(contentsOf: dataUrl!)             //Parse Available Articles             let articles = try // ArticlesParser? JSONDecoder?             self.articles = articles // -- Value of type 'ArticlesInfo' has no property 'articles'         } catch {             print(error)         }     } } So do I need to call articles from ArticlesParser or should I just redefine articles? Hopefully this clears some things up a bit. On the topic of using the Lunch Card method, would using JSON be easier to use than XML? I'm curious because after doing a few tests it seems it's a bit simpler though I haven't tested actually article content (HTML) yet.
Mar ’21
Reply to (Expansion) Call a Class into views
You have no need to (and should not, in this case) make ArticlesParser a local class nested in a function. Good to know. I just need to know where to put this. I will make this a separate thread because this is pretty much the parser I needed. Edit: New thread: https://developer.apple.com/forums/thread/675586
Mar ’21
Reply to (Expansion) Call a Class into views
Sorry for the late reply. A bit confused of how I'm supposed to use ArticlesParser in the ObservableObject. Here's the code so if I missed something, it's here: class ArticlesInfo: ObservableObject {     @Published var articles: [Article] = []          func loadArticles() {         class ArticlesParser: XMLParser {             var dateTimeZone = TimeZone(abbreviation: "GMT-6")             lazy var dateFormater: DateFormatter = {                 let df = DateFormatter()                 df.locale = Locale(identifier: "en_US_POSIX")                 df.dateFormat = "MMM dd, yyyy"                 df.timeZone = dateTimeZone                 return df             }()                          private var textBuffer: String = ""             private var nextArticle: Article? = nil             override init(data: Data) {                 super.init(data: data)                 self.delegate = self // Cannot assign value of type 'ArticlesParser' to type 'XMLParserDelegate?'             }         }         extension ArticlesParser: XMLParserDelegate { // Declaration is only valid at file scope                          // Called when opening tag (`elementName`) is found             func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {                 switch elementName {                 case "posts":                     nextArticle = Article()                 case "title":                     textBuffer = ""                 case "date":                     textBuffer = ""                 case "author":                     textBuffer = ""                 case "img":                     textBuffer = ""                 case "content":                     textBuffer = ""                 default:                     print("Ignoring \(elementName)")                     break                 }             }                          // Called when closing tag (`/elementName`) is found             func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {                 switch elementName {                 case "posts":                     if let article = nextArticle {                         articles.append(article) // Cannot find 'articles' in scope                     }                 case "title":                     nextArticle?.title = textBuffer                 case "date":                     print("date: \(textBuffer)")                     nextArticle?.date = dateFormater.date(from: textBuffer)                 case "author":                     nextArticle?.author = textBuffer                 case "img":                     print("img: \(textBuffer)")                     nextArticle?.img = URL(string: textBuffer)                 case "content":                     nextArticle?.content = textBuffer                 default:                     print("Ignoring \(elementName)")                     break                 }             }                          // Called when a character sequence is found             // This may be called multiple times in a single element             func parser(_ parser: XMLParser, foundCharacters string: String) {                 textBuffer += string             }                          // Called when a CDATA block is found             func parser(_ parser: XMLParser, foundCDATA CDATABlock: Data) {                 guard let string = String(data: CDATABlock, encoding: .utf8) else {                     print("CDATA contains non-textual data, ignored")                     return                 }                 textBuffer += string             }                          // For debugging             func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {                 print(parseError)               print("on:", parser.lineNumber, "at:", parser.columnNumber)             }         }     } }
Mar ’21