Archived: No longer needed
Post
Replies
Boosts
Views
Activity
Here's the new thread:
(Expansion) Call a Class into views - https://developer.apple.com/forums/thread/671482
Please do not ask too many things in a thread. You asked how to use XMLParser and I have shown the answer for it. Understood, I'll create a new thread.
You should read the notes written. Ok, my bad. I apologize.
Question that I just realized needed answered: How would I call ArticlesParser and Article into ArticlesView and other related views (ArticleView, ArticleRow, etc.)?
And I assume Data would be held in Article or ArticlesParser?
I tested out ArticlesParser and it gave me an error.
struct ArticlesView: View {
let fileURL = Bundle.main.url(forResource: "THS", withExtension: "xml")
let parser = ArticlesParser(data: fileURL) // <-- Cannot convert value of type 'URL?' to expected argument type 'Data' & Cannot use instance member 'fileURL' within property initializer; property initializers run before 'self' is available
if parser.parse() { // <-- Expected declaration (in declaration of 'ArticlesView')
print(parser.articles)
} else {
if let error = parser.parserError {
print(error)
} else {
print("Failed with unknown reason")
}
}
//...
}
I was expecting it to read from the XML file (THS.xml) from the app bundle and use the ArticlesParser protocol with it. But instead it threw me those errors. I have a sneaking suspicion that it has to do with the fileURL and how it's called, but I'm not sure what I need to declare by the if statement.
You may not find any third party libraries working unless the XML is designed for a particular library. Good to know.
...you may need to write plenty of code depending on the content of the XML. I expected that.
Thing is, I need to create a whole new XML file because the website (which is built in WordPress) doesn't show all content. I can do that on my own, but how can I use XMLParser to parse that specific data (title, image, author, date, content, etc.) and map it to the specific variables? I'm fine with a reference, but the documentation isn't helping.
Here's an example:
<?xml version=“1.0” encoding “UTF-8”?>
<posts>
<title>New Year, New Resolutions</title>
<date>January 4, 2021</date>
<author>The Hair Society</author>
<img>https://storage.googleapis.com/thehairsociety/2021/01/4a8e3956-bca1f16a-95f3-4f0a-90d5-155fa7194780.jpeg</img>
<content><![CDATA[<span style="font-weight: 400;"><img class="alignright wp-image-19831" src="https://storage.googleapis.com/thehairsociety/2021/01/c4d25cf5-d4b49cc7-c37c-407e-a6a8-a5f36e32a336.jpeg" alt="2021 Resolutions" width="464" height="261" />The year 2021 is here! We've long anticipated this new beginning, and now is the time to buckle down. What will your salon or spa look like in the New Year? If you haven't considered a New Year's resolution, let us help you develop your 2021 game plan.</span>
<span style="font-weight: 400;">First, what is a resolution? A resolution is simply an intention. It is something you aim to do or not to do. It should aid in improving yourself or your business. It is a goal to be better than the year before! Once you've nailed down one or two resolutions for your team, it's time to take action. Here are a few practices that will help you achieve your resolution.</span>
<strong>Start Small</strong>
<span style="font-weight: 400;">Everyone wants to set high expectations, especially after enduring a prior year of hardships. When your initial goal is to increase an asset, you may have to dial it back a few notches. It is easy to become discouraged from the start if your goal is too outlandish. Be sure it is attainable in the next twelve months. For example, if you want to increase your revenue, start with a small percentage of growth. After all, a 10-20% increase is still better than no growth at all. Small wins are still gains. That leads me to my next resolution tip.</span>
<strong><img class="alignleft wp-image-19832" src="https://storage.googleapis.com/thehairsociety/2021/01/573ecc49-9fa635f4-e4e6-4969-8c07-601a7c6f720c.jpeg" alt="New Year Resolution Tips" width="299" height="299" />Measurable Benefits</strong>
<span style="font-weight: 400;">Ask yourself if you can measure the goal for the year. It may require additional data collection methods, but the feedback will prove beneficial in the long run. If you resolve to increase your presence on social media, you can draw your attention to increased followers, the number of "shares" or "likes," etc. Maybe you are aiming to keep a tidy shop in 2021. You'll want to measure client satisfaction with a brief questionnaire or count the number of notable mentions on cleanliness in online reviews.</span>
<span style="font-weight: 400;">A more personal goal for the new year could be organization. How can your team become more organized and then record the benefits? You may track inventory to assess how successful your system of organization. You may begin to notice a change in how a scheduled workday. When your team becomes more organized, the time spent scrambling for misplaced items has now decreased. You may see more time in the workday to increase productivity elsewhere. It is your job to keep a resolution alive throughout the year, so be prepared to measure your hard work.</span>
<strong>Visualize The Steps</strong>
<span style="font-weight: 400;">Your next move is to envision the steps your team will take to succeed. The real changes take place during small acts of progress. Don't intimidate your team with talk about the result. It would be best if you tried to focus on the steps in achievement versus the resolution itself. When your attention is on 2-3 daily tasks, your team can feel empowered to be a piece in the big picture.</span>
<span style="font-weight: 400;">If your salon's resolution is to book more appointments, don't obsess over gaps throughout the day. Instead, your team should encourage booking a client's future appointment weeks in advance and consistently use social media to highlight times of low client volumes. For instance, every Monday, highlight openings for the week on Facebook or Instagram. An online reminder can make all the difference! Not to mention, creating a social media post can be done quickly without taking away from critical salon work.</span>
<strong>More Education</strong>
<span style="font-weight: 400;"><img class="alignright wp-image-19833" src="https://storage.googleapis.com/thehairsociety/2021/01/30bcf8e0-afa6a486-b14f-493d-ae68-9088f9c6debb.jpeg" alt="Continuing Education" width="502" height="251" />Our last resolution tip for success is to encourage lifelong learning. Regardless of your chosen resolution, the hair world is ever-changing. When you think you've learned it all, technology or society reveals new challenges. As our technology or tools change, we must stay updated. You and your team should strive to learn new skills and knowledge.</span>
<span style="font-weight: 400;">What knowledge is essential to study? There are many different hair types out there, and there are also many other conditions that affect hair follicles. Trichology could be the winning edge your team needs to study. Trichology is the science of the hair and scalp. Specializing in medical-related conditions that affect the hair and scalp, a trichologist can care for specific client needs. Although not medically certified as a doctor, a trichologist is trained to treat various client complaints associated with hair and scalp health disorders.</span>
<span style="font-weight: 400;">Arming your team with this knowledge will address hair concerns sooner rather than later. If you can help your clients maintain their hair before a hair loss problem arises, wouldn't you want to? There are many hair care products and treatments trichologists recommend. If your team can connect with a specialist in the hair industry, your salon or spa will provide a holistic approach to caring for clients.</span>
<span style="font-weight: 400;">Move your team into the New Year with resolutions that will stick! As your team continues to put in the hardworking effort month after month, the benefits will soon reap themselves. Happy 2021! </span>]]></content>
</posts>
Note: you'd better not mention the name of your customer. I am not sure they'll appreciate this post so much if they see it. Permission was granted.
Where is the problem ? What do you expect ? What do you get ? The problem? I already identified it. I have no knowledge of how to implement a system to parse XML.
Expectation? To parse the XML data and transfer it to the article title, author, image, date, and content.
What I get? An app with sample data that would destroy the purpose of it being a companion app to the magazine.
I just need some kind of system (whether that be a Swift Package or...) to parse the XML feed of the website to article data.
Archived: Please refer to new thread:
https://developer.apple.com/forums/thread/670984
Actually, ignore this. I've just used the alternative of the inline navigation bar. It seems to complicated to have that kind of title bar be used. Sorry for taking your time!
Please try removing the inner NavigationView, in CardFullView. This method works. But what about ColophonView? That isn't a NavigationView yet it's still having that problem.
Here's where the NavigationLink for ColophonView is located:
SettingsView:
struct SettingsView: View {
@State private var selectedAppearance = 1
@Binding var colorScheme: ColorScheme?
var body: some View {
NavigationView {
Form {
//...
Section {
NavigationLink(destination: ColophonView()) {
Text("Colophon")
}
}
}
.navigationTitle("Settings")
}
.onAppear {
switch colorScheme {
case .none:
selectedAppearance = 1
case .light:
selectedAppearance = 2
case .dark:
selectedAppearance = 3
default:
break
}
}
}
}
Sorry for taking your time. You're totally fine, no need to worry!
I tested this and it worked as expected. Thank you so much!
Here's Info.swift and CardsView:
Info.swift:
//
// Info.swift
// Lunch Card (iOS)
//
// Created by Joshua Srery on 12/21/20.
// Additional code by OOPer on Apple Developer Forums
//
import Foundation
struct CardInfo: Identifiable, Codable {
var name: String = ""
var id: String = ""
var cname: String = ""
// var code: String = ""
}
class CardsInfo: ObservableObject {
@Published var newCard: CardInfo = CardInfo()
@Published var cards: [CardInfo] = []
func add() {
	 cards.append(newCard)
}
}
extension CardsInfo {
var dataUrl: URL {
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
.appendingPathComponent("cards.json")
}
func saveCards() {
do {
let data = try JSONEncoder().encode(cards)
try data.write(to: dataUrl, options: .atomic)
} catch {
print(error)
}
}
func loadCards() {
do {
if FileManager.default.fileExists(atPath: dataUrl.path) {
return
}
let data = try Data(contentsOf: dataUrl)
let cards = try JSONDecoder().decode([CardInfo].self, from: data)
self.cards = cards
} catch {
print(error)
}
}
}
class SheetInfo: ObservableObject {
@Published var showSheetView = false
}
CardsView:
//
// CardsView.swift
// Lunch Card (iOS)
//
// Created by Joshua Srery on 12/17/20.
// Additional code by OOPer on Apple Developer Forums
//
import SwiftUI
struct Card: Identifiable {
let id = UUID()
let title: String
}
struct CardsView: View {
@StateObject var cardsInfo = CardsInfo()
@StateObject var sheetInfo = SheetInfo()
@State private var editMode = EditMode.inactive
@State var presentMode = false
var body: some View {
NavigationView {
List {
ForEach(cardsInfo.cards) { card in
NavigationLink(destination: CardFullView(cname: card.cname, name: card.name, id: card.id)) {
CardRow(cname: card.cname, name: card.name, id: card.id)
}
}
.onDelete(perform: onDelete)
.onMove(perform: onMove)
}.listStyle(PlainListStyle())
.navigationTitle("Cards")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
EditButton()
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
self.sheetInfo.showSheetView.toggle()
}) {
Image(systemName: "plus")
}
}
}
.environment(\.editMode, $editMode)
.sheet(isPresented: $sheetInfo.showSheetView) {
AddView(cardsInfo: cardsInfo, sheetInfo: sheetInfo)
}
.onAppear {
cardsInfo.loadCards() // <- Preferred Placement
}
}
}
private func onDelete(offsets: IndexSet) {
self.presentMode.toggle()
cardsInfo.cards.remove(atOffsets: offsets)
cardsInfo.saveCards()
}
private func onMove(source: IndexSet, destination: Int) {
cardsInfo.cards.move(fromOffsets: source, toOffset: destination)
cardsInfo.saveCards()
}
}
Please tell me if you need more.
I tried different methods of .onAppear in different places:
perform:
.onAppear(perform: cardsInfo.loadCards)
and the content way:
.onAppear {
cardsInfo.loadCards()
}
Neither worked. I was assuming it would save the JSON info from CardInfo and load it the next session, but didn't.
I'll test this and other options out. Thank you!
You need to call cardsInfo.saveCards(), where cardsInfo is the right instance of CardsInfo, maybe some action closure in CardsView. Understood.
Would it work to have cardsInfo.saveCards() as... Another action in the Create button in AddView:
Button(action: {
cardsInfo.add()
cardsInfo.saveCards()
sheetInfo.showSheetView = false
}) {
Text("Create")
.bold()
}
.disabled(self.cardsInfo.newCard.name.isEmpty		self.cardsInfo.newCard.id.isEmpty		self.cardsInfo.newCard.cname.isEmpty)
.foregroundColor(.white)
.padding()
.padding(.horizontal, 100)
.background(Color.accentColor)
.cornerRadius(10)
2. In onDelete
3. In onMove
private func onDelete(offsets: IndexSet) {
self.presentMode.toggle()
cardsInfo.cards.remove(atOffsets: offsets)
cardsInfo.saveCards()
}
private func onMove(source: IndexSet, destination: Int) {
cardsInfo.cards.move(fromOffsets: source, toOffset: destination)
cardsInfo.saveCards()
}
But where would I put cardsInfo.loadCards()? I assume I'd need that to load the saved cards, but I don't know where I'd put that during initial launch.