I writing swift code to change the app icon using setAlternateIconName and flutter MethodChannel to invoke swift.
UIApplication.shared.setAlternateIconName(iconName) { error in
if let error = error {
print("Error setting alternate icon: \(error.localizedDescription)")
result(FlutterError(code: "ICON_CHANGE_ERROR", message: error.localizedDescription, details: nil)) // Send error back to Flutter
} else {
print("App icon changed successfully!")
result(nil) // Success!
}
}
But I got an error message the requested operation couldn't be completed because the feature is not supported when using it on iOS 17+.
So, Is setAlternateIconName still available?
PS. In XCode, the code hinting shows that setAlternateIconName is still not deprecated.
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Post
Replies
Boosts
Views
Activity
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
do {
let shapeLayer = CAShapeLayer()
shapeLayer.frame = CGRect(x: 50, y: 100, width: 200, height: 108)
let path = UIBezierPath(roundedRect: shapeLayer.bounds, cornerRadius: 36)
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.orange.cgColor
view.layer.addSublayer(shapeLayer)
}
do {
let layer = CALayer()
layer.backgroundColor = UIColor.blue.cgColor
layer.cornerRadius = 36
layer.frame = CGRect(x: 50, y: 300, width: 200, height: 108)
view.layer.addSublayer(layer)
}
}
}
The corner radius is set to 36 through CAShapeLayer, but the actual effect is larger than 36, close to half of the height.
Setting it through CALayer is fine
Can anyone explain it to me? Thank you
I have an alertController that is presented as popover on iPad
let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: alertStyle)
if let ppc = alertController.popoverPresentationController {
// …
}
Is it possible to change the message font color (which is really very light on iPad) ?
It is OK on iPhone with the same alert (not popover): text is much more readable:
Hello!
I’m experiencing a crash in my iOS/iPadOS app related to a CALayer rendering process. The crash occurs when attempting to render a UIImage on a background thread. The crashes are occurring in our production app, and while we can monitor them through Crashlytics, we are unable to reproduce the issue in our development environment.
Relevant Code
I have a custom view controller that handles rendering CALayers onto images. This method creates a CALayer on the main thread and then starts a detached task to render this CALayer into a UIImage. The whole idea is learnt from this StackOverflow post: https://stackoverflow.com/a/77834613/9202699
Here are key parts of my implementation:
class MyViewController: UIViewController {
@MainActor
func renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) async -> UIImage? {
// Create CALayer and add it to the view.
CATransaction.begin()
let customLayer = MyDrawingLayer()
customLayer.setupContent(itemsToDraw: itemsToDraw)
// Position the frame off-screen to it hidden.
customLayer.frame = CGRect(
origin: CGPoint(x: -100 - size.width, y: -100 - size.height),
size: size)
customLayer.masksToBounds = true
customLayer.drawsAsynchronously = true
view.layer.addSublayer(customLayer)
CATransaction.commit()
// Render CALayer to UIImage in background thread.
let image = await Task.detached {
customLayer.setNeedsDisplay()
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { // CRASH happens on this line
let cgContext = $0.cgContext
cgContext.saveGState()
cgContext.concatenate(transform)
customLayer.render(in: cgContext)
cgContext.restoreGState()
}
return image
}.value
// Remove the CALayer from the view.
CATransaction.begin()
customLayer.removeFromSuperlayer()
CATransaction.commit()
return image
}
}
class MyDrawingLayer: CALayer {
var itemsToDraw: [MyDrawingItem] = []
func setupContent(itemsToDraw: [MyDrawingItem]) {
self.itemsToDraw = itemsToDraw
}
override func draw(in ctx: CGContext) {
for item in itemsToDraw {
// Render the item to the context (example pseudo-code).
// All items are thread-safe to use.
// Things to draw may include CGPath, CGImages, UIImages, NSAttributedString, etc.
item.draw(in: ctx)
}
}
}
Crash Log
The crash occurs at the following location:
Crashed: com.apple.root.default-qos.cooperative
0 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752)
1 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752)
2 MyApp 0x1a4578 AnyModifier.modified(for:) + 4308649336 (<compiler-generated>:4308649336)
3 MyApp 0x7b4e64 thunk for @escaping @callee_guaranteed (@guaranteed UIGraphicsPDFRendererContext) -> () + 4315008612 (<compiler-generated>:4315008612)
4 UIKitCore 0x1489c0 -[UIGraphicsRenderer runDrawingActions:completionActions:format:error:] + 324
5 UIKitCore 0x14884c -[UIGraphicsRenderer runDrawingActions:completionActions:error:] + 92
6 UIKitCore 0x148778 -[UIGraphicsImageRenderer imageWithActions:] + 184
7 MyApp 0x5cb1c0 closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 100 (FileName.swift:100)
8 libswift_Concurrency.dylib 0x60f5c swift::runJobInEstablishedExecutorContext(swift::Job*) + 252
9 libswift_Concurrency.dylib 0x62514 swift_job_runImpl(swift::Job*, swift::SerialExecutorRef) + 144
10 libdispatch.dylib 0x15ec0 _dispatch_root_queue_drain + 392
11 libdispatch.dylib 0x166c4 _dispatch_worker_thread2 + 156
12 libsystem_pthread.dylib 0x3644 _pthread_wqthread + 228
13 libsystem_pthread.dylib 0x1474 start_wqthread + 8
Questions
Is it safe to run UIGraphicsImageRenderer.image on the background thread?
Given that I want to leverage GPU rendering, what are some best practices for rendering images off the main thread while ensuring stability?
Are there alternatives to using UIGraphicsImageRenderer for background rendering that can still take advantage of GPU rendering?
It is particularly interesting that the crash logs indicate the error may be related to UIGraphicsPDFRendererContext (crash log line number 3). It would be very helpful if someone could explain the connection between starting and drawing on a UIGraphicsImageRenderer and UIGraphicsPDFRendererContext.
Any insights or guidance on this issue would be greatly appreciated. Thanks!!!
I have a setup:
Collection view with compositional layout
a self sizing cell inside
a subview inside the cell
and unrelated view outside the collection view
I would like to:
modify the layout (constraints) of the cell inside the collection view with UIView.animate
trigger an animated layout update of collection view
synchronize the position of an unrelated view to the position of one of the subviews of a collection view cell
What I tried:
UIView.animate(withDuration: 0.25) {
cellViewReference.updateState(state: state, animated: false)
collectionView.collectionViewLayout.invalidateLayout()
collectionView.layoutIfNeeded()
someOtherViewOutsideCollectionView.center = cellViewReference.getPositionOfThatOneViewInWindowCoordinateSystem()
}
What I'm expecting:
after invalidateLayout, the layout update of the collection view is merely scheduled, but not yet performed
layoutIfNeeded forces an update on the collectionViewLayout + update on the frames of the views inside the UICollectionViewCells
all the frames become correct to what they will look like after the animation is performed
I call getPositionOfThatOneViewInWindowCoordinateSystem and it gives me the position of the view after the uicollectionview AND the cell's layout has updated
What happens instead:
getPositionOfThatOneViewInWindowCoordinateSystem returns me an old value
I am observing that the bounds of the cell didn't actually change during layoutIfNeeded
And moreover, the bounds change without animation, instantly
Question:
how to animate self sizing cell size change due relayout
how to synchronize outside views with collection views
I create a notification with an image attachment:
let center = UNUserNotificationCenter.current()
center.delegate = self
let content = UNMutableNotificationContent()
// some more stuff…
let paths = NSSearchPathForDirectoriesInDomains(
FileManager.SearchPathDirectory.documentDirectory,
FileManager.SearchPathDomainMask.userDomainMask, true)
let documentsDirectory = paths[0] as NSString
let fileExtPNG = "#" + "\(imageName)" + " photo.png"
let fileNamePNG = documentsDirectory.appendingPathComponent(fileExtPNG) as String
url = URL(fileURLWithPath: fileNamePNG)
let attachment = try UNNotificationAttachment(identifier: "Image", url: url, options: nil)
content.attachments = [attachment]
I then add the request:
let request = UNNotificationRequest(identifier:requestIdentifier, content: content, trigger: nil)
center.removePendingNotificationRequests(withIdentifiers: [requestIdentifier])
center.add(request) {(error) in }
Problem: when I later test (once notification has been registered), the file do not exist anymore at the url.
I've commented out the add request to confirm.
I have a work around, by creating a temporary copy of the file at the URL and pass it in the attachment.
Then, everything works fine and the copy is deleted.
But that's a bit bizarre. What am I missing here ?
I have a UITextField with UITextContentType equal to oneTimeCode.
It works as expected if the message is in English and the keyword "OTP" exists.
It doesn't work if the message is in Greek and the keyword "OTP" is translated also in greek.
Is the OTP keyword really needed? Is there any alternative? Which are the keywords for any case? Are these keywords only in English?
Thanks in advance!
My app is experiencing a recurring crash in the PRD environment, but it cannot be reproduced locally or in QA testing.
Below is the crash log—I’d appreciate any help or insights on how to diagnose and resolve this issue. Thank you!
0 libobjc.A.dylib 0x2354 objc_release_x0 + 16
1 libobjc.A.dylib 0x2354 objc_release + 16
2 libobjc.A.dylib 0x4e38 AutoreleasePoolPage::releaseUntil(objc_object**) + 204
3 libobjc.A.dylib 0x4b8c objc_autoreleasePoolPop + 260
4 FrontBoardServices 0x1f4d0 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 176
5 FrontBoardServices 0x2eb90 -[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:] + 468
6 libdispatch.dylib 0x3fa8 _dispatch_client_callout + 20
7 libdispatch.dylib 0x79f0 _dispatch_block_invoke_direct + 284
8 FrontBoardServices 0x18378 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 52
9 FrontBoardServices 0x182f8 -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 240
10 FrontBoardServices 0x181d0 -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 28
11 CoreFoundation 0x73f3c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
12 CoreFoundation 0x73ed0 __CFRunLoopDoSource0 + 176
13 CoreFoundation 0x76b94 __CFRunLoopDoSources0 + 344
14 CoreFoundation 0x75d2c __CFRunLoopRun + 840
15 CoreFoundation 0xc8274 CFRunLoopRunSpecific + 588
16 GraphicsServices 0x14c0 GSEventRunModal + 164
17 UIKitCore 0x3ee77c -[UIApplication _run] + 816
18 UIKitCore 0x14e64 UIApplicationMain + 340
When pushing a page in the navigation, changing the state of interactivePopGestureRecognizer causes the page to freeze.
Just like this:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
CGFloat red = (arc4random_uniform(256) / 255.0);
CGFloat green = (arc4random_uniform(256) / 255.0);
CGFloat blue = (arc4random_uniform(256) / 255.0);
CGFloat alpha = 1.0; //
self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0, 0, 100, 44);
btn.backgroundColor = [UIColor redColor];
btn.center = self.view.center;
[btn setTitle:@"push click" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)click:(id)sender {
[self.navigationController pushViewController:[ViewController new] animated:YES];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
@end
Currently I came across an issue in mac catalyst project. All the buttons in my project are not visible, they are in their actual positions and also clickable and performing their tasks as assigned but they are not visible.
When Iam doing:
crossButton.setImage(UIImage(named: "CrossComMac"), for: .normal)
Button does not contain image
While in the below code, image is visible but Iam not able to resize it.
crossButton.imageView?.image = UIImage(named: "CrossComMac")
Also title of the button is not visible too.
Anything related to button in my mac catalyst project is not visible.
Main issue:
Button's image is visible in Xcode running project
Button's image is not visible in build project...(funny thing right)
When picking a photo in the gallery, whatever the orientation of the original image, size is always as landscape
if let image = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.editedImage)] as? UIImage {
print("picked original", image.size)
For a portrait photo:
picked original (1122.0, 932.0)
For a landscape:
picked original (1124.0, 844.0)
What am I missing ?
There are two issues about SFSafariViewController.
After rotate from landscape to portrait,
The topAnchor is destroyed.
The specified bar tint color and control tint color are invalidated.(Returns to system color)
Regarding the second issue, I’ve found a temporary workaround.
Override the viewWillTransition(to:with:) and keep it empty. Don't call super.viewWillTransition(to:with:).
Since UIKit is not open source, I don’t know the exact cause, but I found something that could be the key to the issue. So, I reported it to Apple Feedback Assistant. You can check the details and the sample project in the GitHub repository below.
https://github.com/ueunli/SafariViewer
I have a UITextView being added at runtime to a UIImageView as the result of doing text recognition. It's set to be editable = NO and selectable = YES. When I set the text and select it, it asks the delegate for the menu to display via:
textView:editMenuForTextInRange:suggestedActions:
The suggested items contains many UIAction and UICommand objects that have private methods or do not have the destructive attribute set, yet they are destructive. Some of these are:
promptForReplace:
transliterateChinese:
_insertDrawing:
_showTextFormattingOptions:
I need to return a menu that has only non-destructive commands in it.
First, why isn't UITextView sending only non-destructive suggested commands when its editable is NO?
Second, how can I filter the array of suggested commands when it's impossible to know if they're destructive (as some are missing that attribute)?
In addition to that, even non-destructive commands are causing an unrecognized selector exception, such as the Speak command, which it is sending to my view controller instead of to the UITextView, which is the only thing that knows what the text is that it should speak.
I found a bug in the notes app where if you click on a note the “all iCloud” text will cover over the “all folders” back button and also the “all iCloud” will also hover over the undo button
Getting this error in iPhone Portrait Mode with notch.
Currrently using AVQueuePlayer to play more than 30 mp3 files one by one.
All constraint properties are correct but error occures only in Apple iPhone Portrait Mode with notch series. But same code works on same iPhone in Landscape mode.
**But I get this error: **
LoudnessManager.mm:709 unable to open stream for LoudnessManager plist
Type: Error | Timestamp: 2025-02-07 | Process: | Library: AudioToolbox | Subsystem: com.apple.coreaudio | Category: aqme | TID: 0x42754
LoudnessManager.mm:709 unable to open stream for LoudnessManager plist
LoudnessManager.mm:709 unable to open stream for LoudnessManager plist
Timestamp: 2025-02-07 | Library: AudioToolbox | Subsystem: com.apple.coreaudio | Category: aqme
Hi guys, I’m making a simple note taking app and I want to support markdown functionality. I have tried to find libraries and many other GitHub repos but some of them are slow and some of them are very hard to implement and not very customizable.
In WWDC 22 apple also made a markdown to html document app and I also looked at that code and it was awesome. It was fast and reliable (Apple btw).
But the only problem I am facing is that the markdown text is on the left side and the output format is on the right in the form of html. I don’t want that I want both in the same line. In bear notes and things 3 you can write in markdown and you can see that it is converting in the same line. I have also attached example videos. So, I have markdown parser by apple but the only thing in the way is that it is converting it into a html document. Please help me with this. Also please look into the things 3 video they have also completely customized the text attributes selection menu. By default with UITextView we can only enable text attributes and it shows like this.
By clicking more we get the complete formatting menu but not the slider menu which is more convenient. Please also help me this. I don’t know if I can provide apple file but it is from wwdc 22 supporting desktop class interaction
We are experiencing an issue where UIDocumentPickerViewController causes an uncaught exception when it is dismissed under certain conditions. The error appears as:
<NSXPCConnection: 0x301ac7660> connection from pid 2075 on anonymousListener or serviceListener: Warning: Exception caught during invocation of selector _updateRemoteBarButtonFrames:forUUID:, dropping incoming message and invalidating the connection.
Exception: DocumentManager service tried to send a message to a deallocated host proxy
DocumentManager service tried to send a message to a deallocated host proxy
(
0 CoreFoundation 0x0000000186c2a608 0013A8B1-2524-3534-B5BA-681AAF18C798 + 185864
1 libobjc.A.dylib 0x00000001841a5244 objc_exception_throw + 88
2 Foundation 0x000000018602eec0 E2F95328-659E-3C01-97F7-52B5B3BB7AA5 + 8576704
3 DocumentManager 0x00000002177cf7b8 0BAEFA1B-BD6D-3472-A1B3-6E09F5DE54F2 + 96184
4 CoreFoundation 0x0000000186c2d078 0013A8B1-2524-3534-B5BA-681AAF18C798 + 196728
5 CoreFoundation 0x0000000186c2cef0 _CF_forwarding_prep_0 + 96
6 Foundation 0x00000001858b8d8c E2F95328-659E-3C01-97F7-52B5B3BB7AA5 + 753036
7 Foundation 0x00000001858b7fc8 E2F95328-659E-3C01-97F7-52B5B3BB7AA5 + 749512
8 Foundation 0x00000001858b7220 E2F95328-659E-3C01-97F7-52B5B3BB7AA5 + 746016
9 Foundation 0x00000001858b70d8 E2F95328-659E-3C01-97F7-52B5B3BB7AA5 + 745688
10 libxpc.dylib 0x00000002119f1a50 527F7127-9586-32C8-9D8B-2972D39EAD7A + 72272
11 libxpc.dylib 0x00000002119f35cc 527F7127-9586-32C8-9D8B-2972D39EAD7A + 79308
12 libdispatch.dylib 0x000000010160a638 _dispatch_client_callout4 + 20
13 libdispatch.dylib 0x0000000101627eac _dispatch_mach_msg_invoke + 512
14 libdispatch.dylib 0x000000010161226c _dispatch_lane_serial_drain + 352
15 libdispatch.dylib 0x0000000101628ea4 _dispatch_mach_invoke + 492
16 libdispatch.dylib 0x000000010161226c _dispatch_lane_serial_drain + 352
17 libdispatch.dylib 0x0000000101613290 _dispatch_lane_invoke + 460
18 libdispatch.dylib 0x00000001016206fc _dispatch_root_queue_drain_deferred_wlh + 328
19 libdispatch.dylib 0x000000010161fd0c _dispatch_workloop_worker_thread + 580
20 libsystem_pthread.dylib 0x0000000211998680 _pthread_wqthread + 288
21 libsystem_pthread.dylib 0x0000000211996474 start_wqthread + 8
)
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'DocumentManager service tried to send a message to a deallocated host proxy'
Steps to Reproduce
Present a UIDocumentPickerViewController inside a custom UIViewController.
Dismiss the parent UIViewController before UIDocumentPickerViewController is fully visible.
Swipe down or press the “Cancel” button in the picker.
Occasionally, the system forcefully terminates the view service, causing a crash.
Workarounds Tried (Unsuccessful)
Using UIAdaptivePresentationControllerDelegate – Not Called for UIDocumentPickerViewController.
Using viewDidDisappear to clean up – Not Called when the system terminates the picker.
Forcing dismissal before presenting a new picker
Reference to Line 42 in DOCRemoteViewController.m
From the error traceback, we see a reference to DOCRemoteViewController.m line 42, which strongly suggests that UIDocumentPickerViewController relies on a background process to manage its lifecycle. Since we don’t have access to Apple’s private code, we assume that the DocumentManager service is trying to send a message to an already deallocated instance of UIDocumentPickerViewController, leading to a crash.
One of the example wrapper implementation of us:
class DocumentPickerViewController: UIViewController, UIDocumentPickerDelegate {
private var picker: UIDocumentPickerViewController?
weak var delegate: UIDocumentPickerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
print("📄 DocumentPickerViewController - viewDidLoad() called")
setupDocumentPicker()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("📄 DocumentPickerViewController - viewDidAppear() called")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("📄 DocumentPickerViewController - viewWillAppear() called")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("📄 DocumentPickerViewController - viewWillDisappear() called")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("📄 DocumentPickerViewController - viewDidDisappear() called")
}
deinit {
print("🗑 DocumentPickerViewController - deinit() called")
}
// MARK: - Setup Document Picker
private func setupDocumentPicker() {
picker = UIDocumentPickerViewController(forOpeningContentTypes: [.pdf])
picker?.delegate = self
picker?.allowsMultipleSelection = false
picker?.modalPresentationStyle = .formSheet
if let picker = picker {
present(picker, animated: false) {
print("📄 Document Picker fully presented")
}
}
}
// MARK: - UIDocumentPickerDelegate Methods
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
print("✅ User selected document(s): \(urls)")
delegate?.documentPicker?(controller, didPickDocumentsAt: urls)
dismissSelf()
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
print("❌ User cancelled document selection")
delegate?.documentPickerWasCancelled?(controller)
dismissSelf()
}
private func dismissSelf() {
DispatchQueue.main.async { [weak self] in
self?.dismiss(animated: true)
}
}
}
And logs for this implementation:
📄 Document Picker fully presented
📄 DocumentPickerViewController - viewDidAppear() called
❌ User cancelled document selection
The view service did terminate with error: Error Domain=_UIViewServiceErrorDomain Code=1 "(null)" UserInfo={Terminated=disconnect method}
📄 DocumentPickerViewController - viewDidLoad() called
📄 Document Picker fully presented
📄 DocumentPickerViewController - viewDidAppear() called
would appreciate any workarounds from the community to prevent crashes related to this issue!
In Apple's Maps app, an annotation is made up of a circle shape or rounded rectangles with a glyph-image.
When selecting an annotation, the annotation animates into a balloon marker (see attached GIF).
How does Apple Maps solve this - from custom annotation to balloon marker with spring animation?
I switched my Maps implementation from SwiftUI to UIKit with a UIViewRepresentable to support annotation clustering - and it works beautifully.
But how to subclass an MKAnnotationView (or MKMarkerAnnotationView <- the balloon) to enable selection and animation as in Apple Maps?
MKMarkerAnnotationView only show balloon markers and I tried everything inside MKAnnotationView (CALayer, etc.)
While investigating an apparent IOSurface leak in my app, which makes heavy use of WKWebViews, I found that if I simply create an empty web view and start changing page zoom by pinching, I can see the number of IOSurfaces steadily increasing. Programmatically changing the zoom also has this effect. The controller below gets to 3.58GB of persistent IOSurface objects in about 20 seconds. This behavior continues indefinitely. Is this a leak?
I don't think this is just related to zooming, tapping and scrolling also seem to leak IOSurfaces. The problem I was investigating occurs without any of this, just dynamically modifying a web page containing svgs, but I wonder if this is somehow related, as the allocation stack traces are all the same.
I'm running on iOS 18.1.1 on an iPad Pro 12.9in 4th gen.
class LeakTestController: UIViewController {
private(set) var webView: WKWebView!
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
nil
}
override func viewDidLoad() {
let config = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: config)
view.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: webView.topAnchor),
view.bottomAnchor.constraint(equalTo: webView.bottomAnchor),
view.leadingAnchor.constraint(equalTo: webView.leadingAnchor),
view.trailingAnchor.constraint(equalTo: webView.trailingAnchor)
])
webView.loadHTMLString("hi", baseURL: nil)
startZooming()
}
func startZooming() {
Task.init {
while true {
try await Task.sleep(nanoseconds: 1000000)
webView.pageZoom = 0.5
try await Task.sleep(nanoseconds: 1000000)
webView.pageZoom = 1
}
}
}
}
The stack trace for the allocations is:
IOSurfaceClientLookupFromMachPort
-[IOSurface initWithMachPort:]
WebCore::IOSurface::createFromSendRight(WTF::MachSendRight const&&)
decltype(auto) std::__1::__variant_detail::__visitation::__base::__dispatcher<1ul>::__dispatch[abi:sn180100]<std::__1::__variant_detail::__visitation::__variant::__value_visitor<WTF::Visitor<WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_0, WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_1>>&&, std::__1::__variant_detail::__base<(std::__1::__variant_detail::_Trait)1, WebCore::ShareableBitmapHandle, WTF::MachSendRight>&>(std::__1::__variant_detail::__visitation::__variant::__value_visitor<WTF::Visitor<WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_0, WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)::$_1>>&&, std::__1::__variant_detail::__base<(std::__1::__variant_detail::_Trait)1, WebCore::ShareableBitmapHandle, WTF::MachSendRight>&)
WebKit::RemoteLayerBackingStoreProperties::layerContentsBufferFromBackendHandle(std::__1::variant<WebCore::ShareableBitmapHandle, WTF::MachSendRight>&&, WebKit::LayerContentsType)
WebKit::RemoteLayerTreePropertyApplier::applyPropertiesToLayer(CALayer*, WebKit::RemoteLayerTreeNode*, WebKit::RemoteLayerTreeHost*, WebKit::LayerProperties const&, WebKit::LayerContentsType)
WebKit::RemoteLayerTreePropertyApplier::applyProperties(WebKit::RemoteLayerTreeNode&, WebKit::RemoteLayerTreeHost*, WebKit::LayerProperties const&, WTF::HashMap<WebCore::ProcessQualified<WTF::ObjectIdentifierGeneric<WebCore::PlatformLayerIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>, std::__1::unique_ptr<WebKit::RemoteLayerTreeNode, std::__1::default_delete<WebKit::RemoteLayerTreeNode>>, WTF::DefaultHash<WebCore::ProcessQualified<WTF::ObjectIdentifierGeneric<WebCore::PlatformLayerIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>>, WTF::HashTraits<WebCore::ProcessQualified<WTF::ObjectIdentifierGeneric<WebCore::PlatformLayerIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>>, WTF::HashTraits<std::__1::unique_ptr<WebKit::RemoteLayerTreeNode, std::__1::default_delete<WebKit::RemoteLayerTreeNode>>>, WTF::HashTableTraits> const&, WebKit::LayerContentsType)
WebKit::RemoteLayerTreeHost::updateLayerTree(IPC::Connection const&, WebKit::RemoteLayerTreeTransaction const&, float)
WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree(IPC::Connection&, WTF::Vector<std::__1::pair<WebKit::RemoteLayerTreeTransaction, WebKit::RemoteScrollingCoordinatorTransaction>, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WTF::HashMap<WTF::ObjectIdentifierGeneric<WebKit::RemoteImageBufferSetIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>, std::__1::unique_ptr<WebKit::BufferSetBackendHandle, std::__1::default_delete<WebKit::BufferSetBackendHandle>>, WTF::DefaultHash<WTF::ObjectIdentifierGeneric<WebKit::RemoteImageBufferSetIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>, WTF::HashTraits<WTF::ObjectIdentifierGeneric<WebKit::RemoteImageBufferSetIdentifierType, WTF::ObjectIdentifierMainThreadAccessTraits<unsigned long long>, unsigned long long>>, WTF::HashTraits<std::__1::unique_ptr<WebKit::BufferSetBackendHandle, std::__1::default_delete<WebKit::BufferSetBackendHandle>>>, WTF::HashTableTraits>&&)
WebKit::RemoteLayerTreeDrawingAreaProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&)
IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&)
WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&)
IPC::Connection::dispatchMessage(WTF::UniqueRef<IPC::Decoder>)
IPC::Connection::dispatchIncomingMessages()
WTF::RunLoop::performWork()
WTF::RunLoop::performWork(void*)
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
__CFRunLoopDoSource0
__CFRunLoopDoSources0
__CFRunLoopRun
CFRunLoopRunSpecific
GSEventRunModal
-[UIApplication _run]
UIApplicationMain
0x192173f40
static UIApplicationDelegate.main()
static AppDelegate.$main()
__debug_main_executable_dylib_entry_point
start
Hello!
I discovered a bug on Catalyst about a three years ago but it still seems to be not fixed. My bug report number is FB9705748.
The Internet is silent on this so I'm even not sure, perhaps it's only me.
So to the problem. When you display UICollectionViewController or UIViewController that contains UICollectionView, interact with the collection view then dismiss the view controller, the displayed view controller isn't released if dismissal is done through navigation bar item.
The problem occurs only when the run target is My Mac (Mac Catalyst). Everything is fine when you run on iOS or via My Mac (Designed for iPad).
The sample project is uploaded to GitHub. It has a video that shows this strange behavior, see the log for 'deinit' messages.
I did have some workaround to fix this but it stops to work, presumable on the new macOS. Also, chances are that it's not only UICollectionView which initiates the glitch, it's just that I only encounter it with collection views.