Post

Replies

Boosts

Views

Activity

Reply to Crash on iOS 16.2: -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:
Thanks for the reply. That's not my post on Stackoverflow but I'm experiencing a similar crash that percolates up to -_createPreparedCellForGlobalRow:withIndexPath:willDisplay The crash report for my app doesn't actually get to -tableView:cellForRowAtIndexPath: Instead I can see it all starts from my app checking the .visibleCells property on the table view: 0   CoreFoundation                       0x19c789e48 __exceptionPreprocess + 164 1   libobjc.A.dylib                      0x195a5b8d8 objc_exception_throw + 60 2   Foundation                           0x19704a94c _userInfoForFileAndLine + 0 3   UIKitCore                            0x19eaa0888 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 572 4   UIKitCore                            0x19ea744cc -[UITableView _updateVisibleCellsForRanges:createIfNecessary:] + 596 5   UIKitCore                            0x19e9adb28 -[UITableView _updateVisibleCellsNow:] + 1088 6   UIKitCore                            0x19e9785e8 -[UITableView _visibleCellsUsingPresentationValues:] + 340 7   MyApp                      0x103125120 -[MyTableViewSubclass checkIfLoadingCellIsIsVisible] The checkIfLoadingCellIsIsVisible just enumerates the .visibleCells property on the table view, looking to see if a "loading more" cell is in the visible region of the table view. I've been unable to reliably reproduce the crash. Haven't managed to reproduce it at all when attached to the debugger. I picked up two of these crash reports today since I updated to iOS 16.2.
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst on Multiple Displays: Using UIWindowSceneGeometryPreferencesMac to set a default window size causes new windows to open on the wrong display
I usually don't do this, but I wonder if not enough developers are providing feedback so I'm going to go on a short tangent. Just to go back to my snippet of what I consider to be “normal API”: windowController.window.frame = initialRect; windowController.modelData = modelObject; [windowController showWindow:sender]; This coding style has essentially been “abstracted away” in Catalyst underneath this: NSUserActivity *newWindowActivity = [[NSUserActivity alloc]initWithActivityType:@“my.new.window.activitytype”]; //Our options to pass data to the new window are the following: //Option 1) Write methods to convert a model object to and from one of the types NSUserActivity's userInfo accepts. //Option 2) Make the model object conform to NSSecureCoding and convert it to and from NSData and stuff the NSData in the activity). //Option 3) Pass a "database identifier" and query for the model object on the other end from a singleton and/or database. //In this sample I'm using option 1 because that's the "easiest." Not always possible though. NSArray *modelAsPlist = [modelData propertyListRepresentation]; NSDictionary *modelDictionary = @{@"NewWindowModelData":modelAsPlist}; [newWindowActivity addUserInfoEntriesFromDictionary:modelDictionary]; UISceneActivationRequestOptions *activationOptions = [[UISceneActivationRequestOptions alloc]init]; activationOptions.requestingScene = self.view.window.windowScene; UIApplication *application = [UIApplication sharedApplication]; [application requestSceneSessionActivation:nil userActivity:newWindowActivity options:activationOptions errorHandler:^(NSError * _Nonnull error) { //Whoops the system didn't give me a window. Tough luck. What kind of error handling are application developers expected to do here? }]; And we still haven't achieved the three lines of the "normal API" yet. The controller that needs the model object still hasn't gotten it yet. And the initial frame for the window isn't set. Now on the other end in the UIWindowSceneDelegate: -(void)scene:(UIWindowScene*)scene willConnectToSession:(UISceneSession*)session options:(UISceneConnectionOptions*)connectionOptions { //connectionOptions can have more than 1 activity...we gotta dig for our model object and that's the bottom line because the System says so. NSUserActivity *activityToConfigureWith = nil; for (NSUserActivity *aActivity in connectionOptions.userActivities) { if (aActivity.activityType isEqualToString:@"my.new.window.activitytype"]) { activityToConfigureWith = aActivity; break; } } if (activityToConfigureWith != nil) { NSArray *topLevelModelPlist = activityToConfigureWith.userInfo[@"NewWindowModelData"]; ModelData *model = [ModelData makeWithPropertyList:topLevelModelPlist]; MyViewController *myVC = [[MyViewController alloc]initWithModel:model]; self.window = [[UIWindow alloc]initWithWindowScene:scene]; self.window.rootViewController = myVC; [self.window makeKeyAndVisible]; } else { //Not found. Maybe we have a state restoration activity to configure.. //Or maybe not. Maybe we are just on app launch. We have to sort our way through this pile of user activities just to get started here..it's kind of a mess. } CGRect systemFrame = scene.effectiveGeometry.systemFrame; CGRect newFrame = systemFrame; newFrame.size.width = DEFAULT_WIDTH; newFrame.size.height = DEFAULT_HEIGHT; UIWindowSceneGeometryPreferencesMac *geometryPrefs = [[UIWindowSceneGeometryPreferencesMac alloc]initWithSystemFrame:newFrame]; [scene requestGeometryUpdateWithPreferences:geometryPrefs errorHandler:^(NSError * _Nonnull error) { //Error setting frame. Tough luck! What kind of error handling are application developers expected to do here? }]; } Now in my real app a lot of this code I silo in categories because the amount of code required for such simple tasks is kind of absurd. All we did is 1) create a window 2) set its initial frame and model object and 3) show it on screen. Not sure how this was decided on but IMHO the abstraction is 10x more complex than the internal implementation. At the very least creating and passing data to a new window shouldn't be any harder than creating a new view controller programmatically or using storyboards with -prepareForSegue: But it is a lot harder. And requires lots more boilerplate. This doesn't include the code required to workaround the issue described in FB11885144. If you want to make it easy to port iOS apps to the Mac maybe just expose a NSViewController subclass in the public API that embeds a UIKit view hierarchy inside of it and let developers use them in NSWindows directly? Maybe?
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Sharing Multiple Links at Once on Mac Catalyst Via UIActivityViewController for the Messages Activity?
YES IT IS POSSIBLE! EXCELLENT! Here's something that might be a Catalyst bug, but who knows what they'll say really. My UIActivityItemSource wasn't handling the Messages situation properly because -activityViewController:itemForActivityType: passes in @"com.apple.share.Messages.window" on Catalyst when the Messages activity is selected. This does not match the UIActivityTypeMessage constant, which is @"com.apple.UIKit.activity.Message".
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst on Multiple Displays: Using UIWindowSceneGeometryPreferencesMac to set a default window size causes new windows to open on the wrong display
I can't even try setting the frame from the call site with this API:  [application requestSceneSessionActivation:nil                            userActivity:theActivity                                options:activationOptions                           errorHandler:^(NSError * _Nonnull error)     {     }]; } Because there is an error handler but I don't get back the created UIWindowScene on success.... Is it really necessary to have an error handler on opening a window? An error handler on setting a window's frame? Why is everything hard to do? Passing data to a new window has to be done through these absurd NSUserActivity objects.... Like why isn't there a normal API? windowController.window.frame = initialRect; windowController.modelData = modelObject; [windowController showWindow:sender]; I need an error handler to set a frame and to open a window? Am I making a network request? And if I get an error on set frame how exactly am I supposed to handle the error? Set the frame again and hope that it works?
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst UIWindowScene requestGeometryUpdateWithPreferences: doesn't respect provided systemFrame origin.
So basically what I'm trying to do is this: //Position the window in the center of the screen, initially. UIScreen *targetScreen = scene.screen;  CGRect initialWindowRect = CGRectMake((targetScreen.bounds.size.width/2.0)-(DEFAULT_SIZE.width/2.0),                                      targetScreen.bounds.size.height/2.0-(DEFAULT_SIZE.height/2.0),                                      DEFAULT_SIZE.width,                                      DEFAULT_SIZE.height); Sometimes the origin is ignored (depending whether or not another window is opened, the system adds a default space between open windows. Typically this is how "New Document" windows open on Mac but you wouldn't always want this behavior (for example the "Welcome to Xcode" window always positions itself in the center of the screen when opening). Also is there a way I can compute NSScreen's visibleFrame property from the Mac Catalyst environment so I can position the window relative to the visible frame (the area not including the menu bar and the dock)? UIScreen.bounds property is  (origin = (x = 0, y = 0), size = (width = 1440, height = 900)) but really I'd like to compute the initial window frame relative to NSScreen's .visibleFrame property which would be {{0, 95}, {1440, 780}}
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst UIWindowScene requestGeometryUpdateWithPreferences: doesn't respect provided systemFrame origin.
So the -requestGeometryUpdateWithPreferences:errorHandler: does actually respect the origin if I call the method after a bit of a delay in scene:willConnectToSession:options: I know Catalyst automatically handles the window frame during stare restoration so I need to figure out if there's a way I can ensure my initial frame request won't be called after the system sets the frame on state restoration... because I don't want to break that. Only thing I can think of off the top of my head is maybe saving and restoring the window frame myself in a user activity, though I'm not sure if -requestGeometryUpdateWithPreferences:errorHandler: will respect my requested origin in -scene:restoreInteractionStateWithUserActivity: or if the request is too early their too. I don't really feel like doing this since the user could be on a different display (could close a laptop and connect an external monitor) between save and restored state and I don't feel like implementing frame translation code.
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to How to add add separator menu items on Mac Catalyst?
I have a couple submenus with children I'd like to group together in the context menu. Apparently wrapping them in parent menu like this is how you create a separator:  UIMenu *wrapperMenu = [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:childrenToWrap]; Pretty convoluted but at least it's possible 👍🏻 Tried this earlier and it wasn't working because I think I was hitting the issue where Xcode wasn't compiling the latest code until I cleaned the build folder.
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst UIActivity subclasses that implement the activityViewController property don't work. API is broken.
I don't think I want to burn a TSI on this since I have a workaround though all the available workarounds using public API are not great. On Catalyst you have to manually dismiss the UIActivity's activityViewController property in -activityDidFinish: since the popover holding the UIActivityViewController immediately dismisses after you click the application activity. Also an extra strong reference to the custom UIActivity is required otherwise it gets released with the UIActivityViewController before it has a chance to finish and the abandoned view controller remains in the UI. Another option is to just not use a popover with UIActivityViewController but that isn't Mac like.
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst UIActivity subclasses that implement the activityViewController property don't work. API is broken.
Thanks a lot for the reply. The reason why I invoke -performActivity manually is because I just choose to use this method as the place to "start" the work but it is not at all related to the reported issue. My implementation never calls super and the system does not call -performActivity on an activity that returns an activityViewController. You can rename the -performActivity method in the sample project to any method name you want but the issue will still occur: -(void)_doStartActivityWork {     NSLog(@"start performing...");     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{         [self activityDidFinish:YES];         NSLog(@"Finished performing.");     }); }
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst Make Text in UICollectionViewCell configured with UIListContentConfiguration selectable with mouse/trackpad?
None of the options here are particularly good. Going through your suggestions, I tried making a UITextField look like a label (since that suggestion seemed like the easiest way to achieve the behavior I'm after) but I just couldn't get it to work. I had a UITextField looking like a label by setting it to have no border style and an attributed string that wraps words (I need multiline support too). That looked okay, but couldn't figure out how to make the UITextField "selectable" but not "editable." If I set enabled to NO the text field wouldn't be selectable or editable. If I left the UITextField enabled and tried to suppress editing via the delegate methods, a multiline UITextField would then render the string on a single line when it gets focus (snapping a multiline string to 1 line during text selection isn't going to work). Maybe there is a way to do it with UITextField but I couldn't figure it out.... The thought of using UITextViews and making them look like labels was something I wasn't really willing to try since UITextView is pretty heavyweight. I'm sure it's possible but I wasn't going to go down that road. I need like 20 or so of these "labels" in this UI and these are self sizing cells some with "side by side" text and the window is resizable and the thought of trying to dumb down UITextViews to behave like labels was giving me nightmares. A few years ago I tried putting non editable UITextViews in a UITableView with disastrous results. Maybe it's not that hard though. I didn't really feel like trying it. Embedding SwiftUI is not something I'm going to do here. This view controller is in Objective-C and I don't believe you can use UIHostingConfiguration from Objective-C (at least not easily). I'm definitely not trying to throw out the entire view controller, rewriting the whole thing in Swift with the only tangible benefit being text selection. So I ended up dropping down to TextKit and wrote my own. Not really fun having to spend so much on a feature that desktop platforms typically give us for free. I hope Catalyst will add support for selectable labels in the future since it really is a must have for many Desktop apps. Now I just have to hack my way into NSColor.selectedTextBackgroundColor from the Mac Catalyst environment.... I think Catalyst would be a lot more useful if more of the AppKit APIs were exposed so developers could fallback to it when needed. Support for allowing developers to embed AppKit views in a view hierarchy would be nice too. I could have just embedded a NSTextField instead of a UILabel and been on my way.
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22
Reply to Mac Catalyst Make Text in UICollectionViewCell configured with UIListContentConfiguration selectable with mouse/trackpad?
Yikes, having to throw away my existing cells for such a basic feature is kind of a disappointment and I'm wondering if choosing Mac Catalyst over AppKit was a good choice since I have to roll out a lot of my own stuff to get the behavior you'd expect on a desktop app in many places, and also have to resort to some hacks. I do appreciate your reply though.
Topic: UI Frameworks SubTopic: UIKit Tags:
Dec ’22