Post

Replies

Boosts

Views

Activity

Reply to command executed via `ssh machine bash -c "..."` does not have access to /Volumes
I think I understand the current behaviour. So why was it different before? One thing that has changed is the switch from bash to zsh as the default shell - but that shouldn’t matter if you were explicitly invoking /bin/bash. I don’t believe that the bash or ssh behaviour has changed. Mysterious. Re this example: /usr/bin/ssh max /bin/bash -c "ls /Volumes" That runs this command on the remote machine (note no quotes): /bin/bash -c ls /Volumes According to man bash, the effect of bash -c is that “commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets the name of the shell, which is used in warning and error messages.” So your command just runs ls, while (uselessly) setting $0 to /Volumes. You want to run /bin/bash -c ‘ls /Volumes’ which is what your final version does.
Topic: App & System Services SubTopic: Core OS Tags:
Feb ’25
Reply to Watch-Phone communication when Phone app is in background
Did you try sendMessage(_:replyHandler:errorHandler:)? Calling this method from your watchOS app while it is active and running wakes up the corresponding iOS app in the background and makes it reachable, which I believe is what you are looking for. Consider a simple phone speedometer app. I use CoreLocation to get GPS data and show the speed on the phone screen. It doesn't need to do anything in the background. Now I want to add watch support, sending the speed data from the phone to the watch using the applicationCOntext. (Let's ignore the possibility that the watch app could do this using its own GPS.) Now we need the phone app to run in the background, so that the watch can continue to show the speed when the phone is sleeping. So I enable the location background mode for the phone app and turn on CLLocationManager.allowsBackgroundLocationUpdates. This works but isn't ideal, because for users who don't have a watch etc. we are wasting power on the phone. So we really want to turn allowsBackgroundLocationUpdates on only when the watch app is in use. You suggest that I could use sendMessage(...) to have the watch tell the phone that it is in use. So, on the phone I would implement didReceiveMessage and change allowsBackgroundLocationUpdates. But... is it allowed for an app that has "when in use" location permission to turn on background location updates when it is already in the background? I guess it probably is, but I'll need to check. So when exactly do I want the watch to send its "I'm in use, send data" and "I'm no longer in use, stop sending data" messages? I guess I send them from appropriate WKApplicationDelegate methods. But I don't think I want the phone to turn its location updates on and off every time the user raises or lowers their arm. I guess I can send the messages that frequently, and have the phone app decide whether or not to turn updates off, perhaps with a timeout. Ziqiao, any thoughts about this? Thanks.
Topic: App & System Services SubTopic: Core OS Tags:
Feb ’25
Reply to When is the unverified branch of AppTransaction.shared entered?
if the unverified branch is entered + receipt validation fails, I'll feel OK about marking requests from that app as fraudulent. No, I think that if you get an unverified AppTransaction then you will also fail to verify the receipt on your server. Doing both is probably redundant. Be very cautious about blocking users based on any of this stuff. Assume that they can still write app store reviews when you block them.
Topic: App & System Services SubTopic: StoreKit Tags:
Feb ’25
Reply to SwiftUI and UIImage memory leak
Don’t store UIImages in your model, store the identifiers that you get from the photo picker (i.e. item.itemIdentifier). Then convert to images lazily. Except….. This doesn’t work if the user has granted “limited access” photo library permission. You’ll get identifiers, but you won’t be able to convert them to actual images. (That’s based on the UIKit version of the photo picker, but I guess it is the same here.) So…. if you care about that, you do need to get the image data immediately. There is a note in the docs about it supplying PNG data. I don’t understand the details of that; if that applies here you’ll want to do whatever’s necessary to get JPEG or HEIC or something. Then you need to ask yourself, if it’s unreasonable to have all the uncompressed images in RAM at the same time, is it reasonable or not to have all the compressed images in RAM? If that’s unreasonable, put them in the filesystem. One other thing - you don’t seem to be using thumbnails for your labels, but rather using the full-size UIImage.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jan ’25
Reply to Animate colours in a SwiftUI Canvas
I found this web page: https://swiftui-lab.com/swiftui-animations-part3/ Specifically, the end section where it talks about Animatable Views. Quote: If we want the body of the view to be recomputed for every frame of the animation, then we adopt the Animatable protocol, by adding Animatable, and the animatableData property. So I've replaced the CustomCanvas above with this: struct CustomCanvas: View, Animatable { var fg_colour: Color.Resolved; var animatableData: Color.Resolved { get { fg_colour } get { fg_colour = newValue } }; var body: some View { Canvas { context, size in context.draw(image: Image(name: "foo"), toFitRect: some_rectangle); context.draw(text: Text("foo"), toFitRect: another_rectangle); } .foregroundStyle(fg_colour) } }; and now I pass fg_colour from the MainView: struct MainView: View { @Environment(\.self) var environment; var body: some View { PhaseAnimator([false,true], trigger: foo) { flash in ZStack { Capsule() .foregroundStyle(flash ? .red : .green) CustomCanvas(fg_colour: (flash ? .black : .white) .resolved(in: environment) } } animation: { flash in return .linear(duration: 0.5); } }; (Note Color isn't animatable, but Color.Resolved is; I need some extra stuff to make that work.) But this still doesn't work. The Canvas closure is still only called twice per update, not continuously to update with intermediate colours. Advice would be much appreciated.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jan ’25
Reply to Animate colours in a SwiftUI Canvas
It seems that if I put the Canvas in a custom view, then it is called with flash==false and flash==true, but the colour doesn't transition smoothly from one to the other: (pseduo-code) struct CustomCanvas: View { var body: some View { Canvas { context, size in context.draw(image: Image(name: "foo"), toFitRect: some_rectangle); context.draw(text: Text("foo"), toFitRect: another_rectangle); } } }; struct MainView: View { var body: some View { PhaseAnimator([false,true], trigger: foo) { flash in ZStack { Capsule() .foregroundStyle(flash ? .red : .green) CustomCanvas() .foregroundStyle(flash ? .black : .white) } } animation: { flash in return .linear(duration: 0.5); } };
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Jan ’25
Reply to Error Uploading App: 'A required agreement is missing or has expired'
my Apple Developer Program contract is active until 2026 Well I guess you’ve paid until next year, but that doesn’t necessarily mean that you’ve clicked “accept” on all the required agreements. (You will need to click on updated agreements several times each year.) Go to the website and look for things that you need to click through. It’s unfortunate that the message is not more specific.
Jan ’25
Reply to command executed via `ssh machine bash -c "..."` does not have access to /Volumes
I think I understand the current behaviour. So why was it different before? One thing that has changed is the switch from bash to zsh as the default shell - but that shouldn’t matter if you were explicitly invoking /bin/bash. I don’t believe that the bash or ssh behaviour has changed. Mysterious. Re this example: /usr/bin/ssh max /bin/bash -c "ls /Volumes" That runs this command on the remote machine (note no quotes): /bin/bash -c ls /Volumes According to man bash, the effect of bash -c is that “commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assignment to $0 sets the name of the shell, which is used in warning and error messages.” So your command just runs ls, while (uselessly) setting $0 to /Volumes. You want to run /bin/bash -c ‘ls /Volumes’ which is what your final version does.
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
Feb ’25
Reply to Watch-Phone communication when Phone app is in background
Did you try sendMessage(_:replyHandler:errorHandler:)? Calling this method from your watchOS app while it is active and running wakes up the corresponding iOS app in the background and makes it reachable, which I believe is what you are looking for. Consider a simple phone speedometer app. I use CoreLocation to get GPS data and show the speed on the phone screen. It doesn't need to do anything in the background. Now I want to add watch support, sending the speed data from the phone to the watch using the applicationCOntext. (Let's ignore the possibility that the watch app could do this using its own GPS.) Now we need the phone app to run in the background, so that the watch can continue to show the speed when the phone is sleeping. So I enable the location background mode for the phone app and turn on CLLocationManager.allowsBackgroundLocationUpdates. This works but isn't ideal, because for users who don't have a watch etc. we are wasting power on the phone. So we really want to turn allowsBackgroundLocationUpdates on only when the watch app is in use. You suggest that I could use sendMessage(...) to have the watch tell the phone that it is in use. So, on the phone I would implement didReceiveMessage and change allowsBackgroundLocationUpdates. But... is it allowed for an app that has "when in use" location permission to turn on background location updates when it is already in the background? I guess it probably is, but I'll need to check. So when exactly do I want the watch to send its "I'm in use, send data" and "I'm no longer in use, stop sending data" messages? I guess I send them from appropriate WKApplicationDelegate methods. But I don't think I want the phone to turn its location updates on and off every time the user raises or lowers their arm. I guess I can send the messages that frequently, and have the phone app decide whether or not to turn updates off, perhaps with a timeout. Ziqiao, any thoughts about this? Thanks.
Topic: App & System Services SubTopic: Core OS Tags:
Replies
Boosts
Views
Activity
Feb ’25
Reply to When is the unverified branch of AppTransaction.shared entered?
if the unverified branch is entered + receipt validation fails, I'll feel OK about marking requests from that app as fraudulent. No, I think that if you get an unverified AppTransaction then you will also fail to verify the receipt on your server. Doing both is probably redundant. Be very cautious about blocking users based on any of this stuff. Assume that they can still write app store reviews when you block them.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
Feb ’25
Reply to When is the unverified branch of AppTransaction.shared entered?
Is it when someone has tampered with the app receipt? Yes, and similar. I suggest presenting an alert asking the user to contact you for advice. If you already have some kind of analytics, include this. Don't ignore the possibility of false positives, i.e. users who have made a legitimate purchase but are reported as unverified here.
Topic: App & System Services SubTopic: StoreKit Tags:
Replies
Boosts
Views
Activity
Feb ’25
Reply to SwiftUI and UIImage memory leak
Don’t store UIImages in your model, store the identifiers that you get from the photo picker (i.e. item.itemIdentifier). Then convert to images lazily. Except….. This doesn’t work if the user has granted “limited access” photo library permission. You’ll get identifiers, but you won’t be able to convert them to actual images. (That’s based on the UIKit version of the photo picker, but I guess it is the same here.) So…. if you care about that, you do need to get the image data immediately. There is a note in the docs about it supplying PNG data. I don’t understand the details of that; if that applies here you’ll want to do whatever’s necessary to get JPEG or HEIC or something. Then you need to ask yourself, if it’s unreasonable to have all the uncompressed images in RAM at the same time, is it reasonable or not to have all the compressed images in RAM? If that’s unreasonable, put them in the filesystem. One other thing - you don’t seem to be using thumbnails for your labels, but rather using the full-size UIImage.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jan ’25
Reply to Animate colours in a SwiftUI Canvas
I found this web page: https://swiftui-lab.com/swiftui-animations-part3/ Specifically, the end section where it talks about Animatable Views. Quote: If we want the body of the view to be recomputed for every frame of the animation, then we adopt the Animatable protocol, by adding Animatable, and the animatableData property. So I've replaced the CustomCanvas above with this: struct CustomCanvas: View, Animatable { var fg_colour: Color.Resolved; var animatableData: Color.Resolved { get { fg_colour } get { fg_colour = newValue } }; var body: some View { Canvas { context, size in context.draw(image: Image(name: "foo"), toFitRect: some_rectangle); context.draw(text: Text("foo"), toFitRect: another_rectangle); } .foregroundStyle(fg_colour) } }; and now I pass fg_colour from the MainView: struct MainView: View { @Environment(\.self) var environment; var body: some View { PhaseAnimator([false,true], trigger: foo) { flash in ZStack { Capsule() .foregroundStyle(flash ? .red : .green) CustomCanvas(fg_colour: (flash ? .black : .white) .resolved(in: environment) } } animation: { flash in return .linear(duration: 0.5); } }; (Note Color isn't animatable, but Color.Resolved is; I need some extra stuff to make that work.) But this still doesn't work. The Canvas closure is still only called twice per update, not continuously to update with intermediate colours. Advice would be much appreciated.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jan ’25
Reply to Animate colours in a SwiftUI Canvas
It seems that if I put the Canvas in a custom view, then it is called with flash==false and flash==true, but the colour doesn't transition smoothly from one to the other: (pseduo-code) struct CustomCanvas: View { var body: some View { Canvas { context, size in context.draw(image: Image(name: "foo"), toFitRect: some_rectangle); context.draw(text: Text("foo"), toFitRect: another_rectangle); } } }; struct MainView: View { var body: some View { PhaseAnimator([false,true], trigger: foo) { flash in ZStack { Capsule() .foregroundStyle(flash ? .red : .green) CustomCanvas() .foregroundStyle(flash ? .black : .white) } } animation: { flash in return .linear(duration: 0.5); } };
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Jan ’25
Reply to Error Uploading App: 'A required agreement is missing or has expired'
my Apple Developer Program contract is active until 2026 Well I guess you’ve paid until next year, but that doesn’t necessarily mean that you’ve clicked “accept” on all the required agreements. (You will need to click on updated agreements several times each year.) Go to the website and look for things that you need to click through. It’s unfortunate that the message is not more specific.
Replies
Boosts
Views
Activity
Jan ’25