Posts

Post not yet marked as solved
14 Replies
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)     } }
Post not yet marked as solved
1 Replies
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?
Post not yet marked as solved
7 Replies
Could you provide some code so I can better understand how you’re using Button?
Post not yet marked as solved
14 Replies
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.
Post not yet marked as solved
14 Replies
You continue saying words which I do not understand I added an extension for ArticlesInfo and decided against it. Apologies for not clarifying.
Post not yet marked as solved
14 Replies
What do you mean by integrate? Sorry, meant "merge." There was no point for the extension if the main ObservableObject would just have the variable.
Post not yet marked as solved
14 Replies
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 //... } }
Post marked as solved
4 Replies
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)             }         }     } }
Post marked as solved
4 Replies
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
Post not yet marked as solved
14 Replies
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.
Post not yet marked as solved
14 Replies
You need to pass the right type. Thanks for pointing that out. Your new ArticlesParser lacks the property articles and it does not compile. So do I redefine it? I'm still a little confused.
Post marked as solved
2 Replies
In the latest code for AddView , colorScheme is used. You're right, my mistake.
Post marked as solved
3 Replies
It'd probably be after cards.append(newCard) using the add() function in info. Assign empty to newCard It is better for you to make it by yourself. Good idea. Thanks.
Post marked as solved
1 Replies
Edit: False alarm!! Didn't work after all! Alright, I kinda figured this out myself: I just created a new Xcode project and copied over my code. It's pretty simple.
Post marked as solved
5 Replies
I think it may have been a server problem on Apple's side, because I was finally able to delete the version, but I'll leave this open for anyone else having problems.