With the code below, JSON data is parsed and is stored in the variable data in the .onAppear function, however an empty set of data is passed to the Content view. How can that be fixed so that the JSON data passes to the DataView?
struct ContentView: View {
@State var data: [Data]
@State var index: Int = 0
var body: some View {
VStack {
DataView(data: data[index])
}
.onAppear {
let filePath = Bundle.main.path(forResource: "data", ofType: "json")
let url = URL(fileURLWithPath: filePath!)
data = getData(url: url)
}
}
func getData(url: URL) -> [Data] {
do {
let data = try Data(contentsOf: url)
let jsonDecoded = try JSONDecoder().decode([Data].self, from: data)
return jsonDecoded
} catch let error as NSError {
print("Fail: \(error.localizedDescription)")
} catch {
print("Fail: \(error)")
}
return []
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hello,
I was following a tutorial on how to use the SwiftUI Canvas and I can't seem to get it to work. Below is the code that I have.
struct Line {
var points: [CGPoint]
var color: Color
}
struct CanvasView: View {
@State var lines: [Line] = []
@State var selectedColor: Color = Color.black
var body: some View {
ScrollView([.horizontal, .vertical]) {
Canvas { ctx, size in
for line in lines {
var path = Path()
path.addLines(line.points)
ctx.stroke(path, with: .color(line.color), style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
}
}.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged({ value in
let position = value.location
if value.translation == .zero {
lines.append(Line(points: [position], color: selectedColor))
} else {
guard let lastIndex = lines.indices.last else {
return
}
lines[lastIndex].points.append(position)
}
})
)
}
}
}
I'm pretty sure I followed the tutorial exactly so I'm not sure why it isn't drawing. Any help would be greatly appreciated. Thank you.
Hi,
I am inquiring in regard to how to handle data from a bluetooth device. The device would send data in JSON format to a Mac via bluetooth, and I would need to constantly refresh or fetch data from the device in real time.
How would I go about this? Any help would be greatly appreciated.
Thank you.
Topic:
Programming Languages
SubTopic:
Swift
Tags:
External Accessory
IOBluetooth
Swift
Core Bluetooth
Hi,
I have a button view that is used in many different ways in an app that I'm working on. One of the ways it is used is in an account creation form. Since the button is in a child view, the action: { } button function isn't available in the view where the input field variables are. I could import the class with the function to the button view but I don't want to pass the input field variables into the button view. I tried binding a boolean variable to the button view and checked for it's state change in the parent view using .onChange(), but the use case for that I found was depreciated and I'm unable to revert the state of the variable in the .onChange function.
To reiterate, in a main view, I need to call a function in a given class and pass variables to it, upon a button being pressed in a child view. Any help would be greatly appreciated.
Hi,
I have a struct that I'd like to encode with JSON and send in the body of an HTTP request:
struct AccountCreationData: Codable, Hashable {
var name: String
var email: String
var phone: String
var password: String
private enum CodingKeys: String, CodingKey {
case name
case email
case phone
case password
}
}
I encode it with this code and set the HTTP request body to the encoded data:
guard let encoded = try? JSONEncoder().encode(account) else {
print("Failed to encode request")
return
}
request.httpBody = encoded
But in my backend, when I receive the data from the HTTP request, the JSON data is formatted as such:
'{"phone":"0000000000",
"password":"password",
"email":"email",",
"name":"name"}': ''}
Instead of:
{
"phone": "0000000000",
"password":"password"
"email":"email"
"name":"name"
}
So the JSON parser in my backend isn't properly parsing the data because of the format that the JSON is in. I was wondering if this is an issue with the way I'm encoding on the front end (Swift) or my backend. I have similar projects using the same code to encode the data so I'm unsure as to what the issue is. Any help would be greatly appreciated. Thank you.
I one project, using .onChange(), I get an error: 'onChange(of:initial:_:)' is only available in iOS 17.0 or newer
The solution provided is to wrap the code in if #available(iOS 17.0, *) { }, but I'm only able to wrap the whole view inside of it, like so:
if #available(iOS 17.0, *) {
VStack () {
// view with .onChange
}
} else {
VStack () {
// view with older solution
}
}
The view is quite lengthy so it would be very redundant to have the same view twice, (the same view for each component of the if/else statement). Is there a way to implement an if statement so that I would only need the code for the view once (something like the code below)?
VStack {
}
if #available(iOS 17.0, *) {
.onChange() {
}
} else {
// older solution
}
Additionally, in a newer project, I don't have to include the if #available(iOS 17.0, *) { }, so I'm guessing the build is made for a newer iOS. If that's the case, would it not be compatible with older iOS versions? Any help would be greatly appreciated.
Hi,
I have the following code:
struct Loading: View {
var body: some View {
Text("Loading...")
.onAppear {
print("test")
}
}
}
The view is on the screen, however the print statement doesn't run. Why would this be? Any help would be greatly appreciated.
Hi,
As AppStorage does not support arrays, I found an extension online that allows for handling arrays of strings with AppStorage. However, in my use case, I need to handle arrays of boolean values. Below is the code. Any help would be greatly appreciated.
extension Array: RawRepresentable where Element: Codable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode([Element].self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
}
Hi,
When using just one model container, I have the following code:
let modelContainer: ModelContainer
init() {
do {
entriesModel = try ModelContainer(for: Model.self)
} catch {
fatalError("Could not initialize ModelContainer")
}
}
I am attempting to implement two like so:
let model1: ModelContainer
let model2: ModelContainer
init() {
do {
model1 = try ModelContainer(for: Model1.self)
model2 = try ModelContainer(for: Model2.self)
} catch {
fatalError("Could not initialize ModelContainer")
}
}
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(model1)
.modelContainer(model2)
}
}
However, when in the Views that I'd like to implement I don't know how to declare the models. I tried this:
@Environment(\.model1) private var model1
@Query private var data: [Model1]
But I get the error: Cannot infer key path type from context; consider explicitly specifying a root type
How do I implement multiple model containers in multiple different views?
Hi,
I have a view that should do the following:
Set up and confirm a passcode upon account creation.
Verify passcode if signing in.
Reset passcode if prompted.
With the code below, functions 1 and 2 are working. However, I'm having an issue with function 3. I am able to declare the reset UserDefault on a previous view so that the proper logic occurs, which is to read in the input, and then confirm it. However, it is not working as intended. In this code here:
else if reset {
UserDefaults.standard.set(passcode, forKey: "new-passcode")
UserDefaults.standard.set(false, forKey: "reset-passcode")
passcode = ""
}
I store the new passcode, set reset to false, and clear the passcode so it can be entered again to confirm. The code does not run as intended however. The title does not change and I'm unsure if it is actually storing the passcode. And, when re-entering, it does not change the view as it should by setting view = .someView. I'm assuming there is just flaw in my logic but I'm not sure how to resolve this. Below is the full code. Please let me know if any further clarification is needed.
struct EnterPasscode: View {
@State var title = ""
@State var passcode = ""
@State var message = ""
@State var buttonState = false
@Binding var view: Views
var body: some View {
Group {
Spacer()
.frame(height: 50)
Text(title)
.font(.system(size: 36))
.multilineTextAlignment(.center)
.frame(height: 50)
Spacer()
if passcode != "" {
Text("\(passcode)")
.font(.system(size: 24))
.frame(height: 25)
} else {
Spacer()
.frame(height: 25)
}
Spacer()
.frame(height: 50)
PasscodeKeypad(passcode: $passcode)
Spacer()
if message != "" {
Text(message)
.frame(height: 25)
.foregroundStyle(Color.red)
} else {
Spacer()
.frame(height: 25)
}
Spacer()
WideButton(text: "Continue", buttonFunction: .functional, openView: .enterPasscode, view: .constant(.enterPasscode), buttonState: $buttonState)
.onChange(of: buttonState) { oldState, newState in
if buttonState {
let passcodeSet = UserDefaults.standard.bool(forKey: "passcode-set")
let storedPasscode = UserDefaults.standard.string(forKey: "passcode")
let reset = UserDefaults.standard.bool(forKey: "passcode-reset")
let newPasscode = UserDefaults.standard.string(forKey: "new-passcode")
print(reset)
if passcode.count == 4 {
if storedPasscode == nil {
if newPasscode == nil {
UserDefaults.standard.set(passcode, forKey: "new-passcode")
passcode = ""
} else if passcode == newPasscode {
UserDefaults.standard.set(passcode, forKey: "passcode")
UserDefaults.standard.set(true, forKey: "passcode-set")
view = .someView
}
} else if reset {
UserDefaults.standard.set(passcode, forKey: "new-passcode")
UserDefaults.standard.set(false, forKey: "reset-passcode")
passcode = ""
} else if newPasscode != nil {
if passcode == newPasscode {
UserDefaults.standard.set(passcode, forKey: "passcode")
view = .someView
}
}
}
checkPasscodeStatus()
buttonState = false
}
}
Spacer()
if !UserDefaults.standard.bool(forKey: "passcode-reset") && UserDefaults.standard.bool(forKey: "passcode-set") {
Button(action: {
view = .verifyPhone
}) {
Text("Forgot passcode?")
.foregroundStyle(.black)
}
}
Spacer()
.frame(height: 25)
}
.onAppear() {
checkPasscodeStatus()
}
.frame(width: UIScreen.main.bounds.width - 50)
}
func checkPasscodeStatus() {
let passcodeSet = UserDefaults.standard.bool(forKey: "passcode-set")
let storedPasscode = UserDefaults.standard.string(forKey: "passcode")
let reset = UserDefaults.standard.bool(forKey: "passcode-reset")
if reset {
title = "Enter new passcode"
} else if passcodeSet {
title = "Enter Passcode"
} else if storedPasscode != nil && storedPasscode != "" {
title = "Confirm Passcode"
} else {
title = "Select a 4 Digit Passcode"
}
}
}
struct WideButton: View {
@State var text: String
@State var buttonFunction: ButtonType
@State var openView: Views?
@Binding var view: Views
@Binding var buttonState: Bool
var body: some View {
Button(action: {
buttonPressed()
}, label: {
ZStack {
RoundedRectangle(cornerRadius: 5)
.fill(Color.black)
.frame(width: UIScreen.main.bounds.width - 50, height: 50)
Text(text)
.foregroundColor(.white)
}
})
}
func buttonPressed() {
switch buttonFunction {
case .openView: view = openView!
case .functional: buttonState = true
}
}
}
enum ButtonType {
case openView
case functional
}
Hi,
I tried to make a new branch of my project and upon doing so, all of my old files disappeared. They are no longer in my folder directory or available in Xcode. Please let me know if there is any way to recover these files. I don't see the files in my trash either.
I need to render a PDF and then make it downloadable to the mobile device. I can generate the PDF but I'm unsure how to configure the download aspect. I have the following code:
let renderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: 612, height: 792))
let pdf = renderer.pdfData { (context) in
context.beginPage()
let text = "Test" as NSString
text.draw(in: CGRect(x: 0, y: 0, width: 100, height: 25))
I have the following code for generating a one page PDF:
@MainActor func render() -> URL {
let renderer = ImageRenderer(content: pdfView))
let url = URL.documentsDirectory.appending(path: "output.pdf")
renderer.render { size, context in
var document = CGRect(x: 0, y: 0, width: 2550, height: 3300)
guard let pdf = CGContext(url as CFURL, mediaBox: &document, nil) else {
return
}
pdf.beginPDFPage(nil)
context(pdf)
pdf.endPDFPage()
pdf.closePDF()
}
return url
}
I'm trying to write code to create a multi-page PDF if there is multiple ImageRenderers. I tried something shown below but I'm not sure how to properly implement.
@MainActor func render() -> URL {
let renderer = ImageRenderer(content: pdfView)
let url = URL.documentsDirectory.appending(path: "output.pdf")
for image in renderer {
image.render { size, context in
var page = generatePage(image: image)
}
}
return url
}
func generatePage(image: ImageRenderer<<#Content: View#>>) -> CGContext {
var view = CGRect(x: 0, y: 0, width: 2550, height: 3300)
guard let pdf = CGContext(url as CFURL, mediaBox: &view, nil) else {
return
}
pdf.beginPDFPage(nil)
context(pdf)
pdf.endPDFPage()
pdf.closePDF()
return pdf
}
Any guidance would be greatly appreciated. Thank you.
Hi, I have a couple questions about background app refresh. First, is the function RefreshAppContentsOperation() where to implement code that needs to be run in the background? Second, despite importing BackgroundTasks, I am getting the error "cannot find operationQueue in scope". What can I do to resolve that? Thank you.
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "peaceofmindmentalhealth.RoutineRefresh")
// Fetch no earlier than 15 minutes from now.
request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
func handleAppRefresh(task: BGAppRefreshTask) {
// Schedule a new refresh task.
scheduleAppRefresh()
// Create an operation that performs the main part of the background task.
let operation = RefreshAppContentsOperation()
// Provide the background task with an expiration handler that cancels the operation.
task.expirationHandler = {
operation.cancel()
}
// Inform the system that the background task is complete
// when the operation completes.
operation.completionBlock = {
task.setTaskCompleted(success: !operation.isCancelled)
}
// Start the operation.
operationQueue.addOperation(operation)
}
func RefreshAppContentsOperation() -> Operation {
}
Hello,
I'm using PaintCode for UIGraphics which exports Swift files with an @objc dynamic public class func nested in a NSObject class. With older versions of Swift, could be implemented with the use of a UIKit view and the storyboard.
How could I do this with SwiftUI?
Thanks in advance.