My question pertains to the flow of action messages coming from NSMenuItem. Currently, in my 'Edit' menu, there are menuItems that send cut(_:), copy(_:), paste(_:), delete(_:) to the first responder, and these actions are 'caught' by the viewController.In that same 'Edit' menu, there are 'Undo' and 'Redo'. Before discussing how to to use an NSUndoManager, I would like these actions to be 'caught' by my subclass of NSApplication. Weirdly enough, if the action is called something else then 'undo', like 'undo2', the actions DO make it to my NSApplication subclass. When the action is called 'undo', the action does NOT reach my NSApplication subclass.It seems as though some object somewhere along the responder chain consumes this action. Although checking the responder chain, none of the classes (or superclasses thereof) implement 'undo(_:)'.
Post
Replies
Boosts
Views
Activity
Yes, I am well aware. I studied in detail this documen, yet the undo/redo action messages don't seem to bubble up to NSApplication-subclass.If I implement them in my viewController, and have the validateMenuItems-function returns 'true' for them, the ARE called in the viewController. Walking the nextresponder chain from their, it goes:NSTableView -> NSClipView -> NSScrollView -> NSView -> NSView -> MyViewController -> MyNSWindow -> MyNSWindowControllerSee that there is no MYNSApplication at the end of the line?
Unfortunately not. I gave up on building using that document based stuff. Even if I could get it to work now, it seems very fragile to me, and not something I want to use as a foundation for my app.
Thanks for a your answer Rincewind.
I don't have a particularly large app, there are only 4 or 5 viewcontrollers in total.
The reason I am working with the appearance api is because it seems I have no choice: in when building against iOS16, the navigationbar behaves differently (i.e. it is transparent in iOS16, whereas it is not when building against iOS15).
I came across this thread in which you provided a solution using the appearance api, which makes it seem to me that the only way to solve my original issue is to use the appearance apis.
If there is a way to do update the colors and attributes of a navigationbar 'manually' in iOS16, without using the appearance apis, I would love to hear it. There is only one code-path for this feature, so it would be simple enough (famous last words...).
Thanks, that is helpful!
I think it is important to explain the VC hierarchy a bit (it involves a UIScrollView (well, UICollectionView), which seems to have some acquired 'behind-the-scenes' connections with UINavigationBar)
UIWindow
|-- UINavigationController
|-- CustomContainerViewController (1)
|-- CustomContainerViewController (2) + DrawerViewController // from top side
|-- ContentViewController + DrawerViewController // from right side
CustomContainerViewController (1) contains two viewcontrollers: one filling the view of the container itself, the 'content' which is itself a CustomContainerViewController (the one called CustomContainerViewController (2). The 2nd viewcontroller in this CustomContainerViewController (1) is one that can be pulled down using a 'handle', drawn by the CustomContainerViewController (1), (making it seem as if it is pulled from behind the navigationbar).
CustomContainerViewController (2) is the 'content' of CustomContainerViewController (1). This container has the actual content in it's first viewController, and another viewController that can be pulled in from the right side of the screen, using another 'handle'.
That last one (the one that can be pulled in from the right side of the screen), has a UICollectionView filling the view of that viewController (not sure if this is important).
Here is the code that is called in -application:didFinishLaunchingWithOptions: and in response to a button tapped by the user to change the navigationBar's color:
UIColor *color = ...;
UIColor *textColor = ...;
self.rootNavigationController.navigationBar.barTintColor = color;
self.rootNavigationController.navigationBar.tintColor = textColor;
self.rootNavigationController.navigationBar.translucent = NO;
When building this against iOS16, the app has a transparent UINavigationBar, not what it should be: an opaque color. When those three lines hit, the navigationbar stays transparent.
With a small change (see below), the navigationbar now has the correct color (after this code gets called in application:didFinishLaunchingWithOptions:), but afterwards this code seems to have no effect.
UIColor *color = ...;
UIColor *textColor = ...;
if (@available(iOS 13.0, *))
{
[UINavigationBar appearance].standardAppearance.backgroundColor = color;
[UINavigationBar appearance].compactAppearance = [UINavigationBar appearance].standardAppearance;
[UINavigationBar appearance].scrollEdgeAppearance = [UINavigationBar appearance].standardAppearance;
}
self.rootNavigationController.navigationBar.barTintColor = color;
self.rootNavigationController.navigationBar.tintColor = textColor;
self.rootNavigationController.navigationBar.translucent = NO;
Might this be a bug in the iOS16 sdk?
Thanks for taking the time and effort to bear with me, I appreciate it!
So in your case you should update everything directly. Unfortunately you have to do that for every navigation controller you want to do this with individually.
This is not a problem at all: there is only one navigationbar in my app, and so I am quite happy to update the navigation bar directly. In fact, this is how I wrote it originally, and worked great:
self.rootNavigationController.navigationBar.barTintColor = color;
self.rootNavigationController.navigationBar.tintColor = textColor;
self.rootNavigationController.navigationBar.translucent = NO;
The issue is that this code no longer works when building against iOS16: the navigation bar stays transparent no matter how many times this code is called.
For dynamically changing styles you should instead update the navigation bar directly. As my colleague pointed out the biggest issue with appearance proxy here is that it gets slower every time you request a new proxy (i.e. call -appearance).
So then my question would be: what is the proper way to update the navigation bar directly in iOS16?
Thank you Rincewind, that is th answer that made it all clear to me. I guess I should have l led with my last post when opening this thread. I'm happy it now works, and more importantly, I understand why it works!
Thanks for sharing. I think that article made me see 2 possible benefits, correct me if I’m wrong:
if there is code that never makes its way up to a synchronous context, code will look more linear. Example: downloading some data and persisting it, without directly surfacing the new content in the ui
code that does make its way into a sync context (like my example), will have only a sinlge place where the code is non-linear. Everything behind that function call can be impkemented wit async/await, simplifying the underlying code possibly a lot
Is that about right? Anything else I am missing?
Yes right, thank you. Your first point is indeed a better phrased version of mine. The 2nd point make sense too, and did not occur to me.
I will dive into Swift actors, and look forward to learning how these will help me simplify and strengthen my code.
Thanks for going along with me and help me structure my thoughts!
While waiting for review and approval (seriously?), let me add some relevant info:
Instruments shows that most of the time is being spent in Swifts IndexingIterator.next() function. There is quite a substantial subtree inside it, maybe there is way to reduce the time spent there?
Important to add
let screenWidth: Int = 256 let screenHeight: Int = 240
`
Running this in an optimised build will change the numbers signifcantly. Filling the frame AND generating a CGImage from those raw bytes takes 16 µs (average of a couple of hundred runs)!
The difference between an optimized build and a debug build is quite staggering (to me). Of course that is why profiling gets done on release (i.e. optimized) builds.
I've now been unable to load any app on my device. Here is the exact error I get:
Error mounting image: 0xe8000115 (kAMDMobileImageMounterDevicePropertyQueryFailure: Failed to query device property.)
The developer disk image could not be mounted on this device.
Domain: com.apple.dt.CoreDeviceError
Code: 12040
Failure Reason: Error mounting image: 0xe8000115 (kAMDMobileImageMounterDevicePropertyQueryFailure: Failed to query device property.)
User Info: {
DDIPath = "/Users/Joride/Library/Developer/DeveloperDiskImages/iOS_DDI.dmg";
DVTErrorCreationDateKey = "2024-02-07 12:09:32 +0000";
DeviceIdentifier = "625254F9-0CB7-4135-B261-D73FA85274F3";
IDERunOperationFailingWorker = IDEInstallCoreDeviceWorker;
NSURL = "file:///Users/Joride/Library/Developer/DeveloperDiskImages/iOS_DDI.dmg";
Options = {
MountedBundlePath = "file:///private/var/tmp/CoreDevice_DDI_Staging_501/625254F9-0CB7-4135-B261-D73FA85274F3/";
UseCredentials = 0;
};
"com.apple.dt.DVTCoreDevice.operationName" = enablePersonalizedDDI;
}
--
Error mounting image: 0xe8000115 (kAMDMobileImageMounterDevicePropertyQueryFailure: Failed to query device property.)
Domain: com.apple.mobiledevice
Code: -402652907
User Info: {
FunctionName = AMDeviceRemoteMountPersonalizedBundle;
LineNumber = 2108;
}
--
Failed to initialize remote device attributes: 0xe8000115 (kAMDMobileImageMounterDevicePropertyQueryFailure: Failed to query device property.)
Domain: com.apple.mobiledevice
Code: -402652907
User Info: {
FunctionName = "-[PersonalizedImage mountImage:]";
LineNumber = 1772;
}
--
Failed to retrieve personalization identifiers: 0xe8000115 (kAMDMobileImageMounterDevicePropertyQueryFailure: Failed to query device property.)
Domain: com.apple.mobiledevice
Code: -402652907
User Info: {
FunctionName = "-[PersonalizedImage initializeRemoteDeviceAttributes:]";
LineNumber = 1367;
}
--
Event Metadata: com.apple.dt.IDERunOperationWorkerFinished : {
"device_isCoreDevice" = 1;
"device_model" = "iPhone16,1";
"device_osBuild" = "17.3 (21D50)";
"device_platform" = "com.apple.platform.iphoneos";
"dvt_coredevice_version" = "355.7.7";
"dvt_mobiledevice_version" = "1643.60.2";
"launchSession_schemeCommand" = Run;
"launchSession_state" = 1;
"launchSession_targetArch" = arm64;
"operation_duration_ms" = 230972;
"operation_errorCode" = "-402652907";
"operation_errorDomain" = "com.apple.dt.CoreDeviceError.12040.com.apple.mobiledevice";
"operation_errorWorker" = IDEInstallCoreDeviceWorker;
"operation_name" = IDERunOperationWorkerGroup;
"param_debugger_attachToExtensions" = 0;
"param_debugger_attachToXPC" = 1;
"param_debugger_type" = 3;
"param_destination_isProxy" = 0;
"param_destination_platform" = "com.apple.platform.iphoneos";
"param_diag_MainThreadChecker_stopOnIssue" = 0;
"param_diag_MallocStackLogging_enableDuringAttach" = 0;
"param_diag_MallocStackLogging_enableForXPC" = 1;
"param_diag_allowLocationSimulation" = 1;
"param_diag_checker_tpc_enable" = 1;
"param_diag_gpu_frameCapture_enable" = 0;
"param_diag_gpu_shaderValidation_enable" = 0;
"param_diag_gpu_validation_enable" = 0;
"param_diag_memoryGraphOnResourceException" = 0;
"param_diag_queueDebugging_enable" = 1;
"param_diag_runtimeProfile_generate" = 0;
"param_diag_sanitizer_asan_enable" = 0;
"param_diag_sanitizer_tsan_enable" = 0;
"param_diag_sanitizer_tsan_stopOnIssue" = 0;
"param_diag_sanitizer_ubsan_stopOnIssue" = 0;
"param_diag_showNonLocalizedStrings" = 0;
"param_diag_viewDebugging_enabled" = 1;
"param_diag_viewDebugging_insertDylibOnLaunch" = 1;
"param_install_style" = 0;
"param_launcher_UID" = 2;
"param_launcher_allowDeviceSensorReplayData" = 0;
"param_launcher_kind" = 0;
"param_launcher_style" = 99;
"param_launcher_substyle" = 8192;
"param_runnable_appExtensionHostRunMode" = 0;
"param_runnable_productType" = "com.apple.product-type.application";
"param_structuredConsoleMode" = 1;
"param_testing_launchedForTesting" = 0;
"param_testing_suppressSimulatorApp" = 0;
"param_testing_usingCLI" = 0;
"sdk_canonicalName" = "iphoneos17.2";
"sdk_osVersion" = "17.2";
"sdk_variant" = iphoneos;
}
--
System Information
macOS Version 14.3 (Build 23D56)
Xcode 15.2 (22503) (Build 15C500b)
Timestamp: 2024-02-07T13:09:32+01:00
Hi jblaker,
Did you ever find a solution to this one? If so please share, It might help me with a similar issue: https://forums.developer.apple.com/forums/thread/745840
Cheers,
Joride
If Scrollview is not the right fit, I can probably manage using regular views. I am not looking for user interaction anyway, but to set the offsrt programmatically based on sensor input.