I have a UITableView that supports multiple selection on Mac. My table view also supports swipe actions. When a row is selected and I swipe on another table view row to expose swipe actions, UITableView discards the current selection for seemingly no reason.
To reproduce:
Configure a UITableView that allows multiple selection.
Configure swipe actions.
Run the app. Select a couple rows (via Command click or shift click).
Two finger drag on the track pad to expose a swipe action on another row.
Swipe to hide the swipe actions (not invoking an action).
UITableView discards the entire selection for no apparent reason.
Also the UITableView discards the selection without even informing the delegate (I have a label displaying the selection count in the UI and it still shows the selection count before UITableView clears the selection when a row is swiped).
I don't want to discard the selection just because a swipe action is exposed. I tried working around the problem by reselecting the rows index paths in -tableView:didEndEditingRowAtIndexPath:
-(void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(nullable NSIndexPath*)indexPath
{
//Swipe action is over..fix the selection:
[self reselectIndexPathsAtTheEndOfSwipeActionEditing]; /
}
But when one of the selected index paths is outside the visible region of the table view scroll position jumps after programmatically reselecting the rows which looks wrong...
Anyone have a workaround for this?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
When I set breakpoints on os_log statements like below:
os_log_debug(OS_LOG_DEFAULT, "hi"); //<--break point RIGHT on this line….
I have to click the "Continue Program Execution" button three times to actually continue program execution. At first I thought my method was being called multiple times unexpectedly but it’s not. I just have to keep hitting the continue program execution button. I’m not hitting “Step over” or “step into”. I’m hitting the “Continue Program Execution” button.
FB9792745
I have a UITableView in the supplementary column of a UISplitViewController. Every so often trackpad gestures to reveal swipe actions stop working. I believe the gesture may be getting swallowed by the two finger drag to open the Notification Center but I can't be sure, maybe there's another gesture swallowing it. I keep sliding my fingers to reveal the swipe action with no luck. Eventually swipe actions start working again but it really wouldn't be acceptable for me to ship an app this way.
Anyone else have issues with the swipe gestures on UITableView not working properly? Advice/workarounds are welcomed.
I have a UIActivity subclass that generates data asynchronously. So as an example say we have a "Generate Spreadsheet" activity. In the implementation of the activity:
-(UIViewController*)activityViewController
{
if (_backingViewController == nil)
{
_backingViewController = [[ActivityWithProgressUIViewController alloc]init];
[self performActivity]; // <-- start the activity... always required to manually start the activity when providing a view controller.
}
return _backingViewController;
}// return non-nil to have view controller presented modally. call activityDidFinish at end. default returns nil
Then in -performActivity override...do the work...
-(void)performActivity
{
NSLog(@"start performing...pretend we are creating a spreadsheet..");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self activityDidFinish:YES];
NSLog(@"Finished performing.");
});
}
And that works on iOS. On Mac Catalyst the system never dismisses the view controller returned by UIActivity subclass. Also the UIActivityViewController's completionWithItemsHandler is called immediately after the custom activity is invoked, the system doesn't wait for the custom activity to call -activityDidFinish: The system just leaves the abandoned view controller returned by the custom activity on screen.
Works fine on iOS. Easy to reproduce in a sample project.
On app launch I'm trying to specify a reasonable initial value for the window's frame.
Using the recommended API I create a UIWindowSceneGeometryPreferencesMac object and pass it to -requestGeometryUpdateWithPreferences:errorHandler: in -scene:willConnectToSession:options:
This method respects the value passed in as the size but does not seem to respect the requested origin. Initially I'm always placed at origin 0, 0 for the first window which doesn't look particularly good. I think I'd like to be inset on the x-axis a bit, or maybe even position the window in the center of the screen on app launch.
Is there anyway to get more control over the window frame on Mac Catalyst?
In the WWDC 2022 video "Bring your iOS App to the Mac" there is sample code which shows the recommended way to set the default window size for a new window. According to the presenter it is considered good practice to do this in -scene:willConnectToSession:options:
CGRect systemFrame = scene.effectiveGeometry.systemFrame;
CGRect newFrame = CGRectMake(systemFrame.origin.x,
systemFrame.origin.y,
defaultWindowSize.width,
defaultWindowSize.height);
UIWindowSceneGeometryPreferencesMac *geometryPrefs = [[UIWindowSceneGeometryPreferencesMac alloc]initWithSystemFrame:newFrame];
[scene requestGeometryUpdateWithPreferences:geometryPrefs errorHandler:^(NSError * _Nonnull error)
{
//Error
}];
So I have a button in my UI that opens a new window that uses this window scene delegate class. I have a laptop and external display connected. Now my app's window is on the external display and when I click the button the opens the new window, the new window opens on the laptop's main display (the display physically attached). This is wrong.
Setting the requestingScene property on UISceneActivationRequestOptions makes no difference, the new window still opens on the wrong display no matter what.
If I comment out the above code that sets the initial window size... the window opens on external display as expected (but now I've lost my window size).
According to the UIActivityViewController documentation for UIActivityViewController's completionWithItemsHandler:
Upon the completion of an activity, or the dismissal of the activity view controller, the view controller’s completion block is executed. You can use this block to execute any final code related to the service.
However when invoking the "Messages" or "Mail" actions in the UIActivityViewController this block is never called. I'm presenting the UIActivityViewController in a popover. Simple to reproduce. Just do this on Mac Catalyst in a table view delegate (sorry for the poor code formatting but it is hard to format code well on these forums).
-(UISwipeActionsConfiguration*)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
UIContextualAction *shareAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
title:@"Share"
handler:^(UIContextualAction *action,
UIView * _Nonnull sourceView,
void (^_Nonnull completionHandler)(BOOL))
{
[self showPopoverWithSourceItem:sourceView completionWithItemsHandler:^(UIActivityType _Nullable activityType,
BOOL completed,
NSArray * _Nullable returnedItems,
NSError * _Nullable activityError) {
//This block isn't called when Messages/Mail activities are selected. Probably other too but that's all I tested.
completionHandler(completed); //Need to call the UIContextualAction's completionHandler here to close up the swipe actions.
}];
}];
shareAction.image = [UIImage systemImageNamed:@"square.and.arrow.up.fill"];
UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[shareAction]];
return config;
}
-(void)showPopoverWithSourceItem:(id<UIPopoverPresentationControllerSourceItem>)sourceItem
completionWithItemsHandler:(UIActivityViewControllerCompletionWithItemsHandler)handler
{
NSURL *shareLink = [NSURL URLWithString:@"https://www.apple.com"];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc]initWithActivityItems:@[shareLink]
applicationActivities:nil];
activityViewController.completionWithItemsHandler = handler;
activityViewController.modalPresentationStyle = UIModalPresentationPopover;
UIPopoverPresentationController *presentationController;
presentationController = (UIPopoverPresentationController*)activityViewController.presentationController;
presentationController.sourceItem = sourceItem;
presentationController.permittedArrowDirections = UIPopoverArrowDirectionAny;
[self presentViewController:activityViewController animated:YES completion:nil];
}
Run that and choose "Mail" or "Messages" in the activity view controller. The table view remains swiped after the activity is invoked and the popover is dismissed. Now if you click outside the popover without invoking an activity the popover dismisses and the completionWithItemsHandler is called.
Related but different UIActivityViewController/UIActivity bug I reported here yesterday: https://developer.apple.com/forums/thread/722003
I will file a bug on this and post the number here soon.
Can I please work a full day without running into a system bug in this framework....just one day..please.
I wouldn't be so disgruntled about all this if my obvious bug reports actually got fixed in a reasonable amount of time but I've been a developer long enough to know that I'm lucky if they get fixed for macOS 14, if ever.
Is there any API in Mac Catalyst that wraps the AppKit functionality we get in NSTitlebarAccessoryViewController?
When building context menus in UIKit I often have actions contained in a single method which can be invoked in different ways (from a UIButton, a UIBarButtonItem, etc.)
I'd like to simply make a menu item with a target-action pair but UICommand/KeyCommand only takes a selector. It seems kind of silly to have the system enumerate the responder chain in cases where I know who the target is supposed to be and there can and should only be one target (also could unintentionally create bugs when a responder implementing the same method gets the call instead of the target you want).
In AppKit you an easily do this with NSMenuItem. Could be a nice enhancement in UIKit. I know I can wrap the target in UIAction and call the selector in the action handler block but the code is kind of ugly and I'm not sure if there are edge cases where __weak __strong dance is required (in which case the code is even more long winded and ugly. I know swipe actions can occasionally create a retain cycle if you don't do __weak _ __strong dance).
Unless there is a UIMenuElement subclass that provides this and I'm just not aware of it?
Shortly after presenting a UIDocumentPickerViewController on Mac Catalyst the system throws this exception and I keep hitting my exception breakpoint:
NSView: valueForUndefinedKey this class is not key value coding-compliant for the key cell.
Appears to be related to the system using Touch Bar APIs (my app isn't currently using Touch Bar APIs directly but the NSOpenPanel created by UIDocumentPickerViewController is).
#2 0x0000000198de2828 in -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] ()
#3 0x000000019884ef3c in -[NSObject(NSKeyValueCoding) valueForKey:] ()
#4 0x0000000200b75a68 in -[NSObject(UIAccessibilitySafeCategory) __axValueForKey:] ()
#5 0x0000000200b75960 in __57-[NSObject(UIAccessibilitySafeCategory) safeValueForKey:]_block_invoke ()
#6 0x0000000200b75f9c in -[NSObject(UIAccessibilitySafeCategory) _accessibilityPerformSafeValueKeyBlock:withKey:onClass:] ()
#7 0x0000000200b754d0 in -[NSObject(UIAccessibilitySafeCategory) safeValueForKey:] ()
#8 0x0000000222206b60 in -[NSTouchBarItemAccessibility__UIKit__AppKit _accessibilityPopulateAccessibiltiyInfoFromUIKit] ()
#9 0x0000000222206b1c in -[NSTouchBarItemAccessibility__UIKit__AppKit _itemViewMinSize:maxSize:preferredSize:stretchesContent:] ()
#10 0x000000019b3f70bc in -[NSCompressionGroupLayout item:minSize:maxSize:preferredSize:] ()
#11 0x000000019aff24f4 in -[NSTouchBarItemContainerView _updateMeasuredSizes] ()
#12 0x000000019aff2358 in -[NSTouchBarItemContainerView minSize] ()
#13 0x000000019accae98 in -[NSTouchBarLayout _aggregateWidthOfItems:sharesLeftEdge:sharesRightEdge:widthMeasurement:] ()
#14 0x000000019accb22c in -[NSTouchBarLayout _attributesOfItems:centerItems:givenSize:sharesLeftEdge:sharesRightEdge:xOrigin:] ()
#15 0x000000019acca930 in -[NSTouchBarLayout attributesOfItems:centerItems:givenSize:] ()
#16 0x000000019b52bbb0 in -[NSTouchBarView _positionSubviews] ()
#17 0x000000019b52ba6c in -[NSTouchBarView layout] ()
--
The exception does get caught (my app doesn't crash) but I hit the exception breakpoint over and over again while the NSOpenPanel is on screen which is annoying.
Is there any way to create radio buttons on Mac Catalyst in the Mac idiom (without writing my own from scratch obviously)?
Creating a Settings bundle with PSRadioGroupSpecifier creates a radio button group in the Preference pane but I don't see a way to do this in my own UI?
Is there a way to get native AppKit radio buttons on Mac Catalyst?
Is there any UIKit API that bridges to NSBox in the Mac idiom?
The newer documentation about creating a Settings.bundle on Mac Catalyst simply links out to the Documentation Archive:
https://developer.apple.com/library/archive/documentation/PreferenceSettings/Conceptual/SettingsApplicationSchemaReference/Articles/PSGroupSpecifier.html#//apple_ref/doc/uid/TP40007009-SW1
The SupportedUserInterfaceIdioms key is documented:
Indicates that the element is displayed only on specific types of devices. The value of this key is an array of strings with the supported idioms. Include the string “Phone” to display the element on iPhone and iPod touch. Include the string to “Pad” to display it on iPad.
This key is available in iOS 4.2 and later.
Is "Mac" a supported entry to specify a preference for the Mac idiom? It seems to work but I don't see any documentation for this.
I have a UITabBarController on Mac Catalyst. Since the UITabBar isn't really nice on Mac, I set the UITabBar to hidden.
Then I create a Mac styled NSToolbar with selectable items and manually change the UITabBarController selection with the NSToolbar selection (like the UITabBar would do normally on iOS).
This works fine until I select view controller at index 7 or greater. Then all of a sudden an iOS styled UINavigationBar appears. UITabBarController is wrapping view controllers at index 7 or greater in the "More Navigation Controller" which is not desired or needed (the window width is wide enough to avoid clipping, and the UITabBar is not even visible).
I have an area in my app where I load local HTML strings in WKWebView. Loading is fast on iOS. These local HTML strings are small.
On Mac Catalyst I added the ability to open this area of the UI in a new window scene (new window). And for some reason sometimes when I do this these simple HTML strings can take 10-15 seconds to load in the WKWebview in the new window.
These HTML strings are super small. I key value observed the loading property of the WKWebview and I hold the current date just before calling -loadHTMLString:baseURL:
Then when the web view completes loading I see how much time passed:
-(void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id>*)change
context:(void*)context
{
if (object == self.webview
&& [keyPath isEqualToString:@"loading"])
{
if (!self.webview.isLoading)
{
NSTimeInterval timeInterval = [NSDate.date timeIntervalSinceDate:self.loadStartDate];
NSLog(@"Web view took %f seconds to load",timeInterval);
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
Sometimes it is taking as long as 5 seconds to load a tiny HTML string. When opening these WKWebviews in the same window I don't get these long load times. But when I kick of WKWebView inside a new window scene I often do.