Construct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.

UIKit Documentation

Post

Replies

Boosts

Views

Activity

Setting a tint color for a SF Symbol or System Item using Navigation Controller's UIAppearance API
Hi, I'm working on a View Controller where the Navigation Controller's UIBarButtonItems, composed of SF Symbol images and/or System Items, should change their tint color based on the current Navigation Controller scroll edge or default appearance. let buttonAppearance: UIBarButtonItemAppearance = .init(style: .plain) buttonAppearance.normal.titleTextAttributes = [.foregroundColor: color] standardAppearance.buttonAppearance = buttonAppearance I've used UIBarButtonItemAppearance titleTextAttributes to successfully change a UIButton's label text color, but I wasn't able to find a supported method under the UIAppearance API to do the same update to images. I'd highly appreciate clarification on whether or not it is supported and, if not, what could be some alternatives. Specs: iOS 16+ Thanks!
1
0
588
Dec ’23
App crashed on reading image in bundle when there is only a color with the same name.
Related APIs: +[UIImage imageNamed:] +[UIImage imageNamed:inBundle:compatibleWithTraitCollection:] When there is only a color set with the name (no image set provided), reading the image with the above-mentioned APIs throws an exception: 2023-12-19 19:30:34.008701+0800 ***[57410:578064] *** Assertion failure in -[_UIImageCGImageContent initWithCGImageSource:CGImage:scale:], _UIImageContent.m:666 2023-12-19 19:30:34.031207+0800 ***[57410:578064] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Need an imageRef' Even when wrapped in a try/catch block, it still crashes due to a lock issue after calling the related API twice. Here is an example code snippet: UIImage *image; for (NSInteger i=0; i<10; i++) { @try { image = [UIImage imageNamed:@"sample"]; //image = [UIImage imageNamed:@"sample" inBundle:[NSBundle mainBundle] compatibleWithTraitCollection:nil]; } @catch (NSException *exception) { } } The crash backtrace is as follows: #0 0x0000000102b12214 in _os_unfair_lock_recursive_abort () #1 0x0000000102b0da50 in _os_unfair_lock_lock_slow () #2 0x000000010ab07624 in -[UIImageAsset imageWithConfiguration:] () #3 0x000000010b2f4634 in -[_UIAssetManager imageNamed:configuration:] () #4 0x000000010aaf2394 in +[UIImage imageNamed:inBundle:withConfiguration:] () #5 0x000000010aaf2200 in +[UIImage imageNamed:inBundle:compatibleWithTraitCollection:] () #6 0x0000000105442154 in +[UIImageAccessibility imageNamed:inBundle:compatibleWithTraitCollection:] () It seems that the color set is being treated as an imageRef in this image reading process. It's a bug of UIKit?
1
0
857
Dec ’23
UIViewController asynchronous deallocation issues
i’ve seen evidence that UIViewController has logic to prevent its dealloc/deinit methods from running on a background thread. what seems to occur is that, if the last strong reference to a UIVC is zeroed off the main thread, then the VC is logically marked as ‘deallocating’, but actual invocation of dealloc/deinit is enqueued to the main queue. during the window of time between the beginning and end of this asynchronous deallocation, some strange issues can occur. in particular, if the deallocating VC is a parent view controller, then its children can still access it via their parent property. despite this property being marked as weak, a non-nil parent VC reference will be returned. if a weak reference is attempted to be stored to the parent, you get a runtime crash immediately to the effect of: Cannot form weak reference to instance (0x1234) of class <some-UIVC-sublass>... surprisingly, if you load the reference via the objc runtime's objc_loadWeak method, you'll get nil, but no crash. unsurprisingly, if a strong reference to the deallocating parent is stored and persists past its dealloc invocation, you’ll generally end up with a segmentation violation if the reference is accessed. i imagine the UIVC source is quite complex and there are probably good reasons to try and ensure deallocation only ever occurs on the main thread, but it seems surprising that simply passing view controller variables across threads could lead to exposing unsafe references like this. is this behavior expected? assuming not, i've preemptively filed feedback FB13478946 regarding this issue. attached is some sample code that can reliably reproduce the unexpected behavior. UIKitAsyncDeallocCrashTests.swift
1
0
766
Dec ’23
Custom view animates from bottom - up at first, but not afterwards.
I have this ToastView that will animate by expanding the height from the top of the screen. All the components are created programmatically. This is the code: final class ToastView: UIView { private static let instance = createContainer() private let labelHeightOffset: CGFloat = 32 private let messageLabel: UILabel = { let label = UILabel() label.textAlignment = .center label.numberOfLines = 0 return label }() private var heightConstraint: NSLayoutConstraint! static func show(message: String) { let keyWindow = UIWindow.getKeyWindow() //extension to get the kley window show(on: keyWindow, message: message) } private static func show(on parentView: UIView? = nil, message: String) { guard let parentView = parentView ?? UIViewController.getTopViewController()?.view, instance.superview == nil, let toast = toast else { return } parentView.addSubview(instance, method: .fill) toast.messageLabel.text = message toast.messageLabel.textColor = .red toast.messageLabel.textAlignment = .center toast.messageLabel.sizeToFit() toast.show(for: 3) } private func show(for duration: TimeInterval = 0) { isHidden = false layoutIfNeeded() UIView.animate(withDuration: 0.4, animations: { let labelLineHeight = self.messageLabel.getRect(maxLine: 3).size.height //getRect is an extension func to get the rect based on the content of the label let lineSpaces = CGFloat((self.messageLabel.getLineNumber() - 1) * 2) //getLineNumber is an extension func to get the total number of lines based on the content //Get the height by the content of the label self.heightConstraint.constant = self.labelLineHeight + self.labelHeightOffset + lineSpaces self.setNeedsUpdateConstraints() self.superview?.layoutIfNeeded() }, completion: { _ in self.hide(delay: duration) }) } private func hide(delay: TimeInterval = 0) { UIView.animate(withDuration: 0.4, delay: delay, animations: { self.heightConstraint.constant = 0 self.setNeedsUpdateConstraints() self.superview?.layoutIfNeeded() }, completion: { _ in self.isHidden = true self.messageLabel.text = nil ToastView.instance.removeFromSuperview() }) } } private extension ToastView { static var toast: ToastView? { return instance.subviews[0] as? ToastView } static func createContainer() -> UIView { let container = UIView(frame: .zero) container.backgroundColor = .clear let toast = ToastView(frame: .zero) toast.backgroundColor = .white toast.addCorner(radius: 8) container.addSubview(toast) toast.layoutMessageLabel() toast.layoutToast() return container } func layoutMessageLabel() { addSubview(messageLabel) messageLabel.center = center messageLabel.translatesAutoresizingMaskIntoConstraints = false let constraints = [ centerYAnchor.constraint(equalTo: messageLabel.centerYAnchor), leftAnchor.constraint(equalTo: messageLabel.leftAnchor, constant: 16), rightAnchor.constraint(equalTo: messageLabel.rightAnchor, constant: 16) ] NSLayoutConstraint.activate(constraints) messageLabel.setNeedsUpdateConstraints() layoutIfNeeded() } func layoutToast() { translatesAutoresizingMaskIntoConstraints = false let topConstants: CGFloat = UIWindow.getKeyWindow()?.safeAreaInsets.top ?? 0 + 16 let topConstraint = topAnchor.constraint(equalTo: superview!.topAnchor, constant: topConstants) heightConstraint = heightAnchor.constraint(equalToConstant: 0) let constraints = [ topConstraint, heightConstraint!, leftAnchor.constraint(equalTo: superview!.leftAnchor, constant: 16), superview!.rightAnchor.constraint(equalTo: rightAnchor, constant: 16) ] NSLayoutConstraint.activate(constraints) setNeedsUpdateConstraints() superview!.layoutIfNeeded() } } The code is working fine EXCEPT for the first time it appears. It always animates from the bottom of the screen and rising above ot the top. But if you'll have a look at the code, I only animte the heightConstraint's constant value. Why is this happening? Can you help me fix this? thanks.
1
0
963
Dec ’23
A bug for Accessibility
on iOS, when VoiceOver is running, double click the UITextView can quickly switch the cursor between the beginning and end of the text. Problem the problem is, when the text contains some NSTextAttachment, this ability has failed. Here is some code to reproduce this problem. import UIKit class ViewController: UIViewController { private var textView: UITextView? override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.backgroundColor = UIColor.white textView = UITextView(frame: CGRect(x: 60, y: 220, width: 240, height: 180)) textView?.layer.borderColor = UIColor.black.cgColor textView?.layer.borderWidth = 1 textView?.font = .systemFont(ofSize: 18) view.addSubview(textView!) let button = UIButton(type: .system) button.frame = CGRect(x: 120, y: 120, width: 60, height: 60) button.setTitle("click", for: .normal) button.addTarget(self, action: #selector(self.click), for: .touchUpInside) view.addSubview(button) } @objc func click() { let emojiImage = UIImage(systemName: "iphone.circle") let lineHeight = UIFont.systemFont(ofSize: textView!.font?.pointSize ?? 0.0).lineHeight let insertedAttr = generateAttributedString(image: emojiImage, bounds: CGRect(x: 0, y: -4, width: lineHeight, height: lineHeight)) let attr = NSMutableAttributedString(attributedString: textView!.attributedText) attr.replaceCharacters(in: textView!.selectedRange, with: insertedAttr) textView!.attributedText = attr } public func generateAttributedString(image: UIImage?, bounds: CGRect) -> NSMutableAttributedString { let attachment = NSTextAttachment(data: nil, ofType: nil) attachment.bounds = bounds attachment.image = image let attrString = NSMutableAttributedString(attributedString: NSAttributedString(attachment: attachment)) attrString.addAttribute(.font, value: textView!.font!, range: NSRange(location: 0, length: attrString.length)) return attrString } }
1
0
404
Dec ’23
UILabel bigger font size using a lot of memory
My Keyboard Extension has high memory usage for having UILabels with large font size. The keyboard has emojis in a single view with UICollectionView. I noticed that the bigger font size I use, the more memory usage I have. I set font size approximately to 25 and when scrolling through emojis, the memory usage goes up to 250mb. If I reduce the font size to 10, the memory usage goes down to 70mb when scrolled. The keyboard extension has 75mb memory usage. I've had my keyboard app uploaded for years and had no issues with memory usage but with recent OS update, my keyboard started crashing a lot due to memory usage and it's due to UILabel. Would it be possible to increase the memory limit or exception on the memory usage caused by the OS for large fonts stored as bitmap?
2
0
582
Dec ’23
Back port uniformAcrossSiblings for collection view compositional layout.
This is more of a request I hope y'all will consider. Please back port uniformAcrossSiblings to iOS 13 (or maybe just 15?) (https://developer.apple.com/documentation/uikit/nscollectionlayoutdimension/4173072-uniformacrosssiblings) It's like the iOS 9 UIStackView problem. Amazing new feature nobody can use. Has anyone else done this themselves with either custom or subclass UICollectionViewCompositionalLayout?
0
0
428
Dec ’23
EXC_BREAKPOINT - libobjc.A.dylib object_getClass Crash on the main thread
Having an issue with crashes on iOS 16 and iOS 17 devices. App works and will appear to operate normally. However after a while the app will crash with a EXC_BREAKPOINT on libobjc.A.dylib object_getClass. The root cause seems to be something related to UIViews/Core Animation, I think. However the root crash trigger seems to be a half a dozen different triggers from the UI on main thread. It also only triggers on release builds, or the dev builds take a lot longer to trigger to the point it's very difficult to reproduce. Here are some examples of the crashes occurring. Crashed: com.apple.main-thread 0 libobjc.A.dylib 0xe838 object_getClass + 48 1 Foundation 0x1c854 _NSKeyValueObservationInfoGetObservances + 264 2 Foundation 0x1bd1c NSKeyValueWillChangeWithPerThreadPendingNotifications + 232 3 QuartzCore 0x59408 CAAnimation_setter(CAAnimation*, unsigned int, _CAValueType, void const*) + 128 4 QuartzCore 0x749b4 -[CAAnimation setBeginTime:] + 52 5 QuartzCore 0x728b4 CA::Layer::commit_animations(CA::Transaction*, double (*)(CA::Layer*, double, void*), void (*)(CA::Layer*, CA::Render::Animation*, void*), void (*)(CA::Layer*, __CFString const*, void*), CA::Render::TimingList* (*)(CA::Layer*, void*), void*) + 740 6 QuartzCore 0x2aeac invocation function for block in CA::Context::commit_transaction(CA::Transaction*, double, double*) + 148 7 QuartzCore 0x2adb4 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 368 8 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 9 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 10 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 11 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 12 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 13 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 14 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 15 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 16 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 17 QuartzCore 0x2ad40 CA::Layer::commit_if_needed(CA::Transaction*, void (CA::Layer*, unsigned int, unsigned int) block_pointer) + 252 18 QuartzCore 0x6f548 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 11192 19 QuartzCore 0x65e3c CA::Transaction::commit() + 648 20 UIKitCore 0x924cc _afterCACommitHandler + 84 21 CoreFoundation 0x3583c __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36 22 CoreFoundation 0x34244 __CFRunLoopDoObservers + 548 23 CoreFoundation 0x33960 __CFRunLoopRun + 1028 24 CoreFoundation 0x33478 CFRunLoopRunSpecific + 608 25 GraphicsServices 0x34f8 GSEventRunModal + 164 26 UIKitCore 0x22c62c -[UIApplication _run] + 888 27 UIKitCore 0x22bc68 UIApplicationMain + 340 0 libobjc.A.dylib 0x5d94 object_getClass + 48 1 Foundation 0xadb8 _NSKeyValueObservationInfoGetObservances + 248 2 Foundation 0x3f670 NSKeyValueWillChangeWithPerThreadPendingNotifications + 232 3 QuartzCore 0xbb18 CAAnimation_setter(CAAnimation*, unsigned int, _CAValueType, void const*) + 128 4 QuartzCore 0xcc14 -[CAPropertyAnimation setKeyPath:] + 52 5 QuartzCore 0xcbc0 +[CAPropertyAnimation animationWithKeyPath:] + 36 6 UIKitCore 0xc89fb0 -[UIMorphingLabel animateGlyph:toScale:delay:] + 308 7 UIKitCore 0xc8a1fc -[UIMorphingLabel animateShowGlyph:alpha:alphaDuration:delay:] + 196 8 UIKitCore 0xc8b3f0 -[UIMorphingLabel animateSubstitutionAlignmentHunkAtIndex:] + 1068 9 UIKitCore 0x42cd84 -[UIMorphingLabel animateGlyphs] + 276 10 UIKitCore 0xa374 -[UIMorphingLabel layoutSubviews] + 368 11 UIKitCore 0x4420 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1992 12 QuartzCore 0x9f30 CA::Layer::layout_if_needed(CA::Transaction*) + 500 13 QuartzCore 0x1d4ac CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 148 14 QuartzCore 0x2e8d8 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 444 15 QuartzCore 0x5de80 CA::Transaction::commit() + 648 16 QuartzCore 0x47df0 CA::Transaction::flush_as_runloop_observer(bool) + 88 17 CoreFoundation 0x90234 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36 18 CoreFoundation 0x1a410 __CFRunLoopDoObservers + 532 19 CoreFoundation 0x7a19c __CFRunLoopRun + 1028 20 CoreFoundation 0x7f3ec CFRunLoopRunSpecific + 612 21 GraphicsServices 0x135c GSEventRunModal + 164 22 UIKitCore 0x39cf58 -[UIApplication _run] + 888 23 UIKitCore 0x39cbbc UIApplicationMain + 340 I'm at a loss, I'm clearly doing something wrong in the UIView/Core Animation side of things. Would be very grateful for anyone who can point me in the right direction.
6
1
1.8k
Dec ’23
UIImage.init(named:in:compatibleWith:) different behavior to Image.init(_:bundle:)
I recently observed a distinction in the lookup behavior for an Asset within a specific Bundle when using UIImage.init(named:in:compatibleWith:) compared to Image.init(_:bundle:). Consider a scenario where we have an asset named camera, and there is also an SF symbol with the name camera.fill. We also have an Asset in our Swift Package and use its Bundle. In that case .module. Now, when we use UIImage.init(named:in:compatibleWith:) and inject camera.fill and .module, the result of this initialization is not nil. It appears that UIImage has located something within our Asset. On the other hand, when we inject camera.fill into Image.init(_:bundle:) using the same bundle, the result of this initialization is an empty Image, accompanied by a log entry stating: "No image named 'camera.fill' found in the asset catalog for /Users/.../.bundle." This behaviour aligns with expectations, as we don't have an explicitly named camera.fill within our Assets inside the bundle .module. It appears that even though we injected camera.fill into UIImage.init(named:in:compatibleWith:), it found the first best match, in this case, the camera Asset. Meanwhile, Image.init(_:bundle:) found nothing explicitly named camera.fill within our Assets. Doesn't it seem logical for both of these APIs to yield the same result? Perhaps, it would be even better if both APIs looked up the given name consistently, taking into account the provided bundle in the same way.
0
0
358
Dec ’23
Application Open URL not firing
In my Iphone app, I want to open json files that I have earlier saved. The function I mention below to open the file is not firing when I share a file to my app. I have implemented this in the info.plist file and this seems to work, because in Files I can share a .json file to may app. &lt;key&gt;CFBundleDocumentTypes&lt;/key&gt; &lt;array&gt; &lt;dict&gt; &lt;key&gt;CFBundleTypeName&lt;/key&gt; &lt;string&gt;JSON Document&lt;/string&gt; &lt;key&gt;LSHandlerRank&lt;/key&gt; &lt;string&gt;Alternate&lt;/string&gt; &lt;key&gt;LSItemContentTypes&lt;/key&gt; &lt;array&gt; &lt;string&gt;public.json&lt;/string&gt; &lt;/array&gt; &lt;/dict&gt; &lt;/array&gt; I have added the function to open the file in my AppDelegate file. func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -&gt; Bool { // Handle the file at the given URL // You can perform actions based on the file type or content print("Opening file!") } (the implementation is actually longer to work on the file). When I share a file to my app, the app itself is opening but this method 'application' is never called. I'm not sure whether I'm overlooking something. I have searched quite a while to see what I'm missing. Any help is greatly appreciated! Emile
1
0
540
Dec ’23
Why does the superview of a UITableViewController turns nil after unwindSegue ?
Here is the set up. I have a UITableViewController (controller 1), to which I get from a controller (0) As I need to add a searchView atop the tableView, I addSubview to the superview. This is done in viewWillAppear self.view.superview?.addSubview(searchView) // AboveTableView searchView.isHidden = true print("willAppear", self.view.superview, self.tableView.superview) It works perfectly well, I get: willAppear Optional(<UIViewControllerWrapperView: 0x103d2eef0; frame = (0 0; 393 852); autoresize = W+H; layer = <CALayer: From this VC, I segue to another VC (2) with a show segue and comes back with an unwindSegue to return to (1). Problem is that no, superviews are nil. @IBAction func unwindToTableViewController(_ sender: UIStoryboardSegue) { print("unwind", self.view.superview, self.tableView.superview) } gives unwind nil nil If I step back from this controller (1) to the controller (0) from which I segued and segue again to the TableViewController (1), everything works as expected. In addition, if I go from 1 -> 2 by instantiating (2), everything works OK when I unwind to (1). I know a solution is to refactor code replacing UITableViewController with a UIViewController and embed a TableView inside. But I would like to understand why my present design does not work.
3
0
937
Dec ’23
View appears transparent over tableView, whatever alpha channel
I have a view in storyboard, with a tableView and a coloured UIView. The UIView is declared after tableView, so it appears on top of tableView. However, it appears semi transparent over the tableView. In addition, I cannot set its alpha channel to values other than 1 or 0 (e.g., 0.9) But if I create the view programmatically, the view if fully opaque as expected. What am I missing ?
1
0
823
Dec ’23
UIView (UIButton) Won't re-render after label updates
Situation I am implementing a filter view that has a button to apply the filters selected. The button shows how many results applying the current filters would yield. Like this: The label contains the count variable, the expectation is that when the count updates the button will reflect the new number of results. Current setup I am passing the data (count displayed in the button) like this: ViewModel -> View (SwiftUI) -> View (SwiftUI) -> UIViewControllerRepresentable -> UIViewController. I have validated that the variable that holds the count updates whenever a filter is selected, but the button is not re-rendered to display the new value. Here are some simplified code snippets (In the order described above): ViewModel: @MainActor class ViewModel: ObservableObject { @Published var resultCount: Int = 0 @Published var status: String = "" @Published var type: String = "" init(){ self.addSubscribers() }) } func addSubscribers() { // code here used to filter uses sink based on filters (status and type) selected, this will update resultCount } } ContainerView: struct ContainerView: View { @EnvironmentObject private var vm: ViewModel var body: some View { VStack { FilterView(status: $vm.status, type: $vm.type, resultCount: $vm.resultCount) } } } FilterView: struct FilterView: View { @Binding var status: String @Binding var type: String @Binding var resultCount: Int var body: some View { VStack { FormViewControllerRepresentable(status: $status, type: $type, resultCount: $resultCount, showFilterSelectionView: $showFilterSelectionView) } } } FormViewControllerRepresentable: struct FormViewControllerRepresentable: UIViewControllerRepresentable { @Binding var status: String @Binding var type: String @Binding var resultCount: Int func makeUIViewController(context: Context) -> FilterFormViewController { FilterFormViewController(status: $status, type: $type, resultCount: $resultCount) } func updateUIViewController(_ uiViewController: FilterFormViewController, context: Context) { uiViewController.status = status uiViewController.type = type uiViewController.resultCount = resultCount } } UIViewController class FilterFormViewController: UIViewController, UITextFieldDelegate { @Binding var status: String @Binding var type: String @Binding var resultCount: Int @Binding var showFilterSelectionView: Bool init(status: Binding<String>, type: Binding<String>, resultCount: Binding<Int>, showFilterSelectionView: Binding<Bool>) { self._status = status self._type = type self._resultCount = resultCount self._showFilterSelectionView = showFilterSelectionView super.init(nibName: nil, bundle: nil) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } lazy var formView = Form() let stackView = UIStackView() let scrollView = UIScrollView() override func viewDidLoad() { super.viewDidLoad() setup() } func setup() { // set delegate for Picker (filters) formView.statusPicker.textField.delegate = self formView.statusPicker.delegate = self formView.typePicker.textField.delegate = self formView.typePicker.delegate = self stackView.addArrangedSubview(getButtonsStackView()) scrollView.addSubviews([stackView]) view.addSubview(scrollView) } func getButtonsStackView() -> UIStackView { // HERE is the button. even though resultCount updates, the button is not re-rendered // UIButton here is actually a custom component that conforms to UIButton. In the custom component setTitle(label, for: .normal) is called let submitButton = UIButton( label: "Show \(self.resultCount) results") submitButton.isEnabled = true submitButton.addTarget(self, action: #selector(hideFilters), for: .touchUpInside) let buttonsView = UIStackView( arrangedSubviews: [ submitButton ] ) return buttonsView } func textFieldDidEndEditing(_ textField: UITextField) { // getters here are working well and setting the value for status & type is updating the variable in the viewModel // THE PROBLEM IS: While this updates the value for the filters and that in turns updates the result count, the button won't re-render with the new value status = formView.getStatus() type = formView.getType() } }
1
1
424
Dec ’23
NSInternalInconsistencyException crash in iOS 17
Hey Team, We started to get the NSInternalInconsistencyException crash only for iOS 17. The crash logs are very generic and don’t point to any specific screen or code that’s why it's hard to figure out the root cause for this. We already tried running the main thread checker but we didn’t get any thread issues. Kindly help. Crash Logs: Fatal Exception: NSInternalInconsistencyException Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread. 0 CoreFoundation 0xec870 __exceptionPreprocess 1 libobjc.A.dylib 0x2bc00 objc_exception_throw 2 CoreAutoLayout 0x56c8 NSISSparseVectorAddTermWithPlaceValueCoefficientStartingIndex 3 CoreAutoLayout 0xbadc -[NSISEngine _optimizeWithoutRebuilding] 4 CoreAutoLayout 0xb7f0 -[NSISEngine optimize] 5 CoreAutoLayout 0xb57c -[NSISEngine performPendingChangeNotifications] 6 UIKitCore 0x33f38 -[UIView(Hierarchy) layoutSubviews] 7 UIKitCore 0x32694 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] 8 QuartzCore 0x671c0 CA::Layer::layout_if_needed(CA::Transaction*) 9 QuartzCore 0x66d48 CA::Layer::layout_and_display_if_needed(CA::Transaction*) 10 QuartzCore 0x6d278 CA::Context::commit_transaction(CA::Transaction*, double, double*) 11 QuartzCore 0x66574 CA::Transaction::commit() 12 QuartzCore 0x1fe504 CA::Transaction::release_thread(void*) 13 libsystem_pthread.dylib 0x9f48 _pthread_tsd_cleanup 14 libsystem_pthread.dylib 0x4880 _pthread_exit 15 libsystem_pthread.dylib 0x5d7c _pthread_wqthread_legacy_worker_wrap 16 libsystem_pthread.dylib 0x19ec _pthread_wqthread 17 libsystem_pthread.dylib 0x1a04 start_wqthread
9
2
2.4k
Dec ’23
Stutter and lose frame on RTL long texts
Hi guys, I am developing an app which is a messaging app and it needs to work smoothly. However, I ran into an issue where I couldn't scroll over RTL text properly. It doesn't matter whether I am using UIKit or SwiftUI it just stutters. I tested out on an iPad with a promotion display / iPhone XS and 15 pro-Max and the result was the same. Someone said using an RTL font could resolve the issue however it did not. And if you uncomment the line 48 and comment the line 49 you will see the app run smoothly without a hitch. It is overtly clear in messaging apps that the app stutters, and our users have complained about it a lot. struct UItableViewTest: View { var body: some View { SwiftUI.NavigationStack { NavigationLink { RandomItemsTableViewControllerWrapper() } label: { Text("move to table view controller") } } } } struct RandomItemsTableViewControllerWrapper: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UIViewController { return RandomItemsTableViewController() } func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} } class RandomItemsTableViewController: UITableViewController { private let cellReuseIdentifier = "Cell" private var items: [String] = [] private let font = UIFont(name: "RTLFONT", size: 16) override func viewDidLoad() { super.viewDidLoad() generateRandomItems() tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) } private func generateRandomItems() { let maxRTLLength = MockTexts.rtlText.count let numberOfItems = 100 for _ in 0..<numberOfItems { let randomLength = Int.random(in: 10...maxRTLLength) let randomRTL = Bool.random() // let randomText = String(MockTexts.loremIpsum.prefix(randomLength)) let randomText = String(randomRTL ? MockTexts.rtlText.prefix(randomLength) : MockTexts.loremIpsum.prefix(randomLength)) items.append(randomText) } } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return items.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) cell.textLabel?.text = items[indexPath.row] cell.textLabel?.numberOfLines = 0 cell.textLabel?.font = font return cell } } #Preview { UItableViewTest() } struct MockTexts { static let loremIpsum = """ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed commodo gravida sagittis.\n Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \n Nam eleifend metus leo, id maximus ante posuere ac.\n Fusce ultrices fringilla malesuada.\n Sed eget lectus ut nisl condimentum scelerisque.\n Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed commodo gravida sagittis.\n Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \n Nam eleifend metus leo, id maximus ante posuere ac.\n Fusce ultrices fringilla malesuada.\n Sed eget lectus ut nisl condimentum scelerisque.\n Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed commodo gravida sagittis.\n Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \n Nuada.\n Sed eget lectus ut nisl condimentum scelerisque.\n Pellentesque habit Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed commodo gravida sagittis.\n Nulla facilisi. Vesti Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed commodo gravida sagittis.\n Nulla facilisi. Vestiabitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed commodo gravida sagittis.\n Nulla facilisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \n Nam eleifend metus leo, id maximus ante posuere ac.\n Fusce ultrices fringilla malesuad\n te ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; \n Nam eleifend metus leo, id maximus ante posuere ac.\n Fusce ultrices fringilla malesuada.\n Sed eget lectus ut nisl condimentum scelerisque.\n Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. """ static let rtlText = """ سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. سلام این یه متن طولانی است که من برای تست دارم می نویسم ببینم چه جوری کار میکنه متن های خیلی طولانی فارسی. """ }
0
0
347
Dec ’23
How can I use this code in ContentView with the default augmented reality template provided by Xcode
Hey guys, I hope you are all doing well! I am really stuck on a problem and I need help here. I am new to Swift but I need to use Swift to complete a project. I am trying to use this code https://github.com/jmousseau/RoomObjectReplicatorDemo/blob/main/RoomObjectReplicatorDemo/ViewController.swift with the RoomObjectReplicator library https://github.com/jmousseau/RoomObjectReplicator. However, the issue is that my app is currently using SwiftUI and not UIKit. Furthermore, I have ContentView and ARViewContainer. How can I implement the code but use ContentView and ARViewContainer along with SwiftUI? Thanks in advance!
0
0
441
Dec ’23
HTML tags in UILabel don't work
Hi, I've got this html text: "<style>* {font-size: 12pt !important;color: #000000 !important;font-family: Montserrat-Regular !important;}</style>Perform the following steps:<br><u>Option 1:</u><br><p>1) Upon receiving a push notification alert, tap on the push notification to launch BIMB Authenticator</p><p>2) Verify the transaction details and choose \"Approve\"</p><p>3) Complete</p><br><u>Option 2:</u><br><ol><p>1) If you didn’t receive push notification, you may launch BIMB Authenticator</p><p>2) Verify the transaction details and choose \"Approve\"</p><p>3) Complete</p>" And I'm trying to show this HTML text properly in a UILabel. This is my codes: String extension to map to NSAttributedString: extension String { func attributedStringFromHTML() -> NSAttributedString? { guard let data = "\(self)" .data(using: .utf8, allowLossyConversion: false) else { Log.error(category: .transaction, message: "Unable to decode data from html string: %@", self) return nil } let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [ .documentType: NSAttributedString.DocumentType.html, .characterEncoding: String.Encoding.utf8.rawValue ] if let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) { return attributedString } else { Log.error(category: .transaction, message: "Unable to create attributed string from html string: %@", self) return nil } } } And this is the result: Can you tell me how to fix this? Thanks.
0
0
766
Dec ’23