SwiftUI Crash LayoutComputer.EngineDelegate.sizeThatFits? - ios

I can't identify the source of this crash, and when I "Open in Project" Xcode doesn't point to any particular area of my code. What could be causing this? It seems to be when a certain button is tapped.

Solution
After I ran into this same sort of problem, the solution for me, was to clean my build folder, then perform a full build of my application for my target device, as opposed to not cleaning my build folder, and just performing an incremental build of my app.
Steps I followed to trigger this bug, and to resolve my issue
I had an Xcode Project, containing:
A Swift Package I'd added as a "Local Swift Package" which contained:
A module that defined a public method (let's call it modifyListRow) in an extension of the View protocol.
My SwiftUI Application for iOS which contained:
My #main App which rendered a SwiftUI View that contained:
List { ForEach { MyRow.modifyListRow() } }
I then did a full build & run of my app - which depended on that Local Swift Package, and after the app launched on my physical iPhone X device, I saw that everything worked properly.
I then modified the body of the modifyListRow method, in such a way that it would affect how the sizes of the List-rows produced by the ForEach View should be calculated by the SwiftUI Framework.
I then did an incremental build and run of my app.
This time, after my app launched on my iPhone, I just saw a blank screen in it because SwiftUI had failed to render any of my app's views, and I saw in Xcode that my app had crashed while attempting to calculate a sizeThatFits for a view - presumably for one of the List-rows produced by my ForEach View.
I then cleaned my build folder, and did a full build & run of my project, and after the app launched on my iPhone, I saw that this time everything worked properly.
Hypothesis of cause of bug for my app
Presumably, Xcode had cached the compiled code for my SwiftUI View that contained the List after I did the first full build, but didn't invalidate the compiled code for that View, despite the fact I'd modified the body of the modifyListRow method in such a way that the List-rows would have needed to have their sizes calculated differently by the SwiftUI Framework. This made it so that my SwiftUI View would not be re-compiled during the incremental build I'd performed, despite the fact the modifyListRow method was re-compiled. Consequently, the compiled code of my SwiftUI View and the modifyListRow method became "out-of-sync" in the build artefact, and hence, the SwiftUI framework failed to calculate the sizes of the List-rows. But cleaning my build folder, and performing a full-build, made it so that my SwiftUI View would be re-compiled, along with the modifyListRow method, and hence, the compiled code for my SwiftUI View and the modifyListRow method resumed being "in-sync" in the build artefact just as they originally had been. This made it so that the SwiftUI Framework would be able to successfully calculate the sizes of the List-rows.
But please remember, this is just my hypothesis as to the cause of the bug for my app - it may be incorrect.

Related

SwiftUI Preview timeout for large project

I've been trying to preview SwiftUI files in my large iOS project and cannot get past this error TimeoutError: Timed out waiting for a thunk to build after 30.0 seconds.
What's interesting/confusing is that a newly created SwiftUI file with the default "Hello World" Text does successfully load the preview in the same project, however more complex SwiftUI files show the time out error even when I change the preview struct to display a Text("Hello World") view.
Has anyone else experienced this or could point in what direction I can dig to fix this timeout issue?
In case it helps someone else... I ended being able to load the previews by temporarily setting the project to iOS 13 development target (normally it's iOS 12). Thankfully we'll be dropping iOS 12 soon so this won't be an issue after that.
I just fixed it on my project after leaving it be for several days cause I couldn't figure out.
So as the log mentionned, I had to "break down" my View code in smaller chunks. First identify where in the view does the compiler complain by commenting parts of it. Then when you identified the piece of code that's causing the issue create new separate views from it and call them in place of the big chunk. From my part I had a List row made of an HStack wich contained a Text and Textfield. The compiler didn't like that at all. I just put the HStack in a new view and called it in the same place and problem solved.

How to dismiss the UIActivityViewController during a UI test with Xcode 11 & iOS 13

Apple has re-designed the share sheet that appears, which has now broken my UI tests.
I have attempted to record a new UI test through Xcode, but as soon as I tap on the dismiss button, the test terminates so I have not been able to capture the event.
Ultimately, I just want to know how I can access the gray 'X' shown with the arrow below:
I have just tested this with Xcode 13 and have found that the original answer no longer works. However, I am keeping it for posterity, or those using previous versions of Xcode.
Xcode 13
I have tested this with Xcode 13.0 and verified it works for iPhone and iPad:
let activityListView = app.otherElements.element(matching: .other,
identifier: "ActivityListView")
XCTAssertTrue(activityListView.waitForExistence(timeout: 2.0))
activityListView.buttons["Close"].tap()
Previous versions
After some trial and error, I was able to locate where my specific elements were with the following:
app.otherElements.element(boundBy: 1).buttons.element(boundBy: 0).tap()
Using app.otherElements.element(boundBy: 1) would identify the share sheet for me. I had attempted to locate it through accessibility identifiers, but I could not find one that worked, including previously valid ones used in iOS 12 and below.
Please note that based on the layout of your screen, the index value
may differ from what I am seeing.
Next, .buttons.element(boundBy: 0).tap() was used to locate the Close button. I again attempted to use identifiers, but could not find anything that represented the button.
When I attempted to discern additional information through the console while testing, I would always wind up crashing the test. This result was surprising, as I was able to query these elements with Xcode 10.
Ultimately, I would like to find working identifier values so that I can have something that works reliably across products, without the trial and error to find the share sheet's index value.
For iPad
The following will dismiss the popover for an iPad:
app.otherElements["PopoverDismissRegion"].tap()

IB Designables: Failed to render and update auto layout status - The agent crashed

I am working on an existing iOS Project in Xcode 10.2.1 on macOS 10.14.4. The uses mainly Objectiv-C but also some Swift Pods (v. 1.5.2). Recently I have also added the first Swift based ViewController using Swift 5.
The Problem:
When working on the XIB file of this Swift bases ViewController after a short time the following error message is shown in the Xcode sidebar:
IB Designables: Failed to render and update auto layout status for
ViewXYZ (abc-de-123): The agent crashed
As soon as there error occur no changes in the Interface Builder (added view, changed colors, text, etc.) are shown anymore. When I re-open the XIB file it only show grey view placeholders instead of the real content.
The problem can only be solved by re-starting Xcode but when working on the XIB again it shows up after again after just a few moment.
Things that did NOT work
Since the problem is realted to IB Designabales I checked these first. Within the ViewController I am using two different custom views which are implemented in Objective-C and marked as IB_DESIGNABLE.
These views have not been changed recently and it was never a problem to use them before. Removing all custom code from these views did not change the problem. Thus there seems to be nothing wrong with the implementation.
I found other topics dealing with similar issues, but none of the different solutions worked for me:
Re-starting the Mac, re-starting Xcode, cleaning the build folder or deleting ~/Library/Developer/Xcode/DerivedData does NOT solve the problem
Adding this code to the pod file does NOT solve the problem
Adding all UIView constructors to the views as proposed here does NOT solve the problem.
Xcode shows that the designables are up to date and does NOT offer a debug button (as shown here)
The views do not have orphant outlets
Re-creating the XIB from scratch let to the same issue
Not using the Bundle or other device specific code within the custom views did NOT solve the problem. As described before I removed ALL custom code from the classes so that they where simple UIView subclasses without any changes.
So far nothing I tried had any effect. However, most answers I found are quite old. Are there are any new proposals to solve this issue?

iOS TodayView Widget breakpoints not working

I'm working through this tutorial and it works just fine on a simulator, except I don't understand how the methods are being called. The today view widget displays fine but when I add breakpoints to the methods (e.g. ViewDidLoad, widgetPerformUpdateWithCompletionHandler) the breakpoints never seem to be called.
I'm trying to figure this out as I've added extra code - e.g. NSLog to display some values within the methods but do not see any output from the NSLog calls.
Can someone explain why the breakpoints are not working? I'm guessing that it has something to do with the extension methods are executing in the 'background' but am not sure.
Thanks
You are able to have the breakpoints you set in your today extension activate by following the procedure below:
1) Set breakpoint in your extension code (viewDidLoad is a good option to test)
2) Launch your app as you normally would by selecting your app's target and hitting run.
3) Make sure that your extension is installed in the today view (open the today view and hit the edit button to add it if it is not)
4) Close the today view.
5) In Xcode select your today extension target and press the run button. You will be prompted to choose an app to run. Select "Today".
6) You should see the today window appear on the simulator (this also works on the device). Your breakpoint will be hit.
NOTE: You may hit an exception breakpoint in your app prior to the today extension launching because your app is sent to the background. If this happens just skip over the breakpoint and you will hit the breakpoint in your extension as expected. This procedure also allows you to see console statements from your extension.
I'm not sure if this is related to your specific situation, but in an app where I have 3 extensions, I noticed that breakpoints don't work in 2 of them.
I noticed however, that the breakpoints start working if I run (from XCode) the extension on which the breakpoints work, and access one of the other extensions (from inside Photos app in my case). For some reason, running the other extensions from XCode would not trigger the breakpoints.

WatchKit reloadRootControllersWithNames causing error, with pageController or after push/pop

I have a basic watchkit app that loads a page based navigation of 3 interface controllers. This works well, but I'd then like to trigger an action to remove the page-control and essentially revert back to the original InterfaceController that was present when the app first loads.
// load page based control, with 3 views. this works ok
[WKInterfaceController reloadRootControllersWithNames:#[#"pageController1",#"pageController2",#"pageController3"]
contexts:#[#"data1",#"data2",#"data3"]];
// attempt to reload original interface controller, identified by storyboard id
[WKInterfaceController reloadRootControllersWithNames:#[#"myInterfaceController"] contexts:#[#{}]];
The page based navigation remove, the original navigation loads after a short spinner. However it fails to function correctly and original Actions result in this error.
Extension[6766:123665] *********** ERROR
-[SPRemoteInterface _interfaceControllerClientIDForControllerID:] clientIdentifier for interfaceControllerID:(null) not found
Is there a better way to cleanly reload the original InterfaceController?
EDIT, 2/19
It seems there are some other actions that are causing this error too. For instance, if segue to a second InterfaceController and then popController to get back, the error often appears. It is always related to a secondary call to this function.
[WKInterfaceController reloadRootControllersWithNames: contexts:]
EDIT2, 3/18
As previously mentioned, this is reproducible 100% of the time by doing the seguePush, the popController, then attempting to reloadRootControllersWithNames.
If the seguePush/popController is not done beforehand, then the reloadRootControllersWithNames will work fine.
This situation seems to be in addition to the multi->single-multi instance of this bug.
This is actually not a bug because according to Apple:
You cannot combine hierarchical and page-based interface styles. At design time, you must choose the style that best suits your app’s content and design for that style.
So unfortunately, we can't mix Hierarchical and Page-based navigation patterns within the same Watch app.
Just one of many limitations we have to deal with when developing apps for  Watch
This is a bug in WatchKit in Xcode 6.2 Beta 5. Please dupe the following radar on Apple's Bug Reporting System to help raise the priority to get this fixed.
In the meantime, a workaround that I've found can be found on the dev forums. What you can do is add a dummy interface controller to any single interface controller page set so you always have two. This will fix the error until Apple get's the bug fixed (hopefully in Beta 6). Please dupe!
I was able to solve my instance of this problem by not using popController on a pushed view controller. Instead I use a reloadRootControllersWithNames in place of the popController.
How this allows both push and paging, via an example:
Push a view controller
reloadRootControllersWithNames to return to the original controller. (The transition is not quite as animated, but is sufficient)
Create page based view controller.
reloadRootControllersWithNames to return to the original controller
Repeat 1 or 3 as needed.
This eliminates the error at the cost of non-animated popControllers, and allows partial pushing and paging. It would not allow more complex push navigation though.
There may be a better method of navigating to a sub interface controller without a push call, but I'm not aware of it on the watch yet.
None or the answers above worked for me. This problem began when I changed the icon names for the app and the watch app name. I solved it like this:
1) Click on your Watch app Target > Capabilities > make sure app Group
is in ON.
2) Make sure the App Group is selected.
3) Clic on the circled arrow Refresh icon (this will apparently just
refresh this thing if you already had it)
4-Repeat steps 1-3, but for your Watch App EXTENSION target too.
5-Click on the Scheme button (on the right side of the STOP button),
and clic on Edit Schemes.
6-Click Run > Info 7-In executable select your target (Actually it
should already be selecting but opening this window seems to
refresh the option, and wipe the error)
Apparently all these things above are not updated automatically when you change the icon name (Target names) and you have to go to those menus and open them to refresh them manually. Shame on Apple perhaps?

Resources