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

UIKit Documentation

Post

Replies

Boosts

Views

Activity

CNContactViewController blocking Home gesture after presenting the "Add Photo" View Controller in iOS 17
Hello I'm currently having some issues when using CNContactViewController in iOS 17. The problem starts after embedding the CNContactViewController inside a UINavigationController and presenting it modally. The CNContactViewController is created using the forNewContact initialiser and passing an initial value to it (CNMutableContact) Next I tap the Add Photo button, which presents the new iOS 17 Photo Editor/Picker which immediately covers all the screen. After pressing Cancel, the Photo Editor is dismissed but the "Go Home" gesture is disabled and its not possible to go to the Home Screen unless the iPhone screen is turned off and on again (this fixes the issue). This seems to be a bug in this CNContactViewController unless I'm using it incorrectly. Additionally, this is only happening when the Photo Editor is cancelled/dismissed. If the whole process of picking and editing a photo is completed, this issue does not happens and the "Go Home" gesture works as usual. Here is a code sample of how CNContactViewController being used and presented: class ContactViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let b = UIButton(type: .system) b.setTitle("Push", for: .normal) b.setTitleColor(.systemBlue, for: .normal) b.addTarget(self, action: #selector(pushAction(sender:)), for: .touchUpInside) b.translatesAutoresizingMaskIntoConstraints = false view.addSubview(b) NSLayoutConstraint.activate([ b.centerXAnchor.constraint(equalTo: view.centerXAnchor), b.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } @objc func pushAction(sender: UIButton) { let mc = CNMutableContact() mc.givenName = "MyName" let vc = CNContactViewController(forNewContact: mc) vc.allowsActions = false vc.allowsEditing = false vc.contactStore = CNContactStore() vc.delegate = self let nc = UINavigationController(rootViewController: vc) nc.modalPresentationStyle = .fullScreen self.present(nc, animated: true) } } extension ContactViewController: CNContactViewControllerDelegate { func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?) { viewController.dismiss(animated: true) } }
0
0
619
Mar ’24
UIDocumentPickerViewController dismisses twice
Hi! I've found that when presenting a UIDocumentPickerViewController, if you quickly tap twice on a document, both the picker view controller AND its parent view controller gets dismissed. My guess is that the system simply fires off a dismissal twice, closing both views. It's easier to trigger on a simulator than on a real device. Any way to get around this? I guess it would be possible to monitor dismissals and intercept any undesired ones, but it's not great.
0
0
365
Mar ’24
Couldn't read values in CFPrefsPlistSource when presenting UIActivityViewController
When I try to display a UIActivityViewController, I get funky logging in the xcode console. This is my code: @IBAction func shareAction(_ sender: Any) { // text to share let text = "Some very interesting text!" let url = Constants.URL.appStore.absoluteString guard let logo = UIImage(named: "App Logo")? .circle() .resize(333, 333) else { return } // set up activity view controller let itemsToShare: [Any] = [ logo, text, url ] let activityViewController = UIActivityViewController(activityItems: itemsToShare, applicationActivities: nil) activityViewController.popoverPresentationController?.sourceView = self.view // exclude some activity types from the list if #available(iOS 15.4, *) { activityViewController.excludedActivityTypes = [ .airDrop, .sharePlay ] } else { activityViewController.excludedActivityTypes = [ .airDrop ] } // present the Share Sheet self.present(activityViewController, animated: true, completion: nil) } The logging emerges in the console as soon as the code calls: self.present(activityViewController, animated: true, completion: nil) When I set a break point on that line, no logging occurs. If I add a completion block to that call with a break point on the first line, the logging occurs before it hits that break point. so all logging seems to be generated while displaying the UIActivityViewController. This is my logging Cannot issue sandbox extension for URL:https://apps.apple.com/app/id Couldn't read values in CFPrefsPlistSource<0x303b38900> (Domain: com.apple.country.carrier_1, User: kCFPreferencesCurrentUser, ByHost: No, Container: /var/mobile/Library/CountryBundles/, Contents Need Refresh: No): accessing preferences outside an application's container requires user-preference-read or file-read-data sandbox access Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)}> (501) personaAttributesForPersonaType for type:0 failed with error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction.} Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port Received port for identifier response: <(null)> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port <0x10640ca30> Gesture: System gesture gate timed out. Line 2, 5, 7, 9 are red the other lines are yellah I have been looking on the internet and found nothing. I have been looking in this forum, and found one possible match (without a solution): https://forums.developer.apple.com/forums/thread/746721 When looking through the logging: 'entitlement com.apple.runningboard.primitiveattribute' Should I add something to my entitlements to be allowed to show a UIActivityViewController? Is that the solution? If so: How do I add that entitlement? (or any of the other entitlements mentioned there) And since when is that required?? The app (and this feature) seem to work like a charm ... so I could ignore. Only I find it difficult to ignore RED logging by xcode. If it is red, it is bound to be kinda serious, right? Or is there a whole other reason / cause why I suddenly get this? Now running: xcode Version 15.3 (15E204a) iOS 17.4.1
1
0
1.1k
Mar ’24
Strange UICollectionView diffable data source crash on ios 17
After using xcode 15 for distribution we are having strange crashes from UICollectionViewDiffableDataSource. Crash does not indicate any call stack from our own code. This happens on %100 ios 17 and with xcode 15.1 build and we can not reproduce it in testing environment. Here is the stack trace Crashed: com.apple.main-thread 0 libswiftCore.dylib 0x40369c swift_getObjectType + 40 1 UIKitCore 0x469160 __swift_destroy_boxed_opaque_existential_1Tm + 35088 2 UIKitCore 0x2633ac -[__UIDiffableDataSource collectionView:cellForItemAtIndexPath:] + 144 3 UIKitCore 0x466fd4 __swift_destroy_boxed_opaque_existential_1Tm + 26500 4 UIKitCore 0x4670e0 __swift_destroy_boxed_opaque_existential_1Tm + 26768 5 UIKitCore 0xd2194 -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:notify:] + 668 6 UIKitCore 0x65f674 -[UICollectionView _prefetchItemsForPrefetchingContext:] + 384 7 UIKitCore 0x32204c -[UICollectionView _updatePrefetchedCells:] + 148 8 UIKitCore 0x6613fc -[UICollectionView _updateCycleIdleUntil:] + 492 9 UIKitCore 0xa69a5c ___UIUpdateCycleNotifyIdle_block_invoke + 596 10 libdispatch.dylib 0x213c _dispatch_call_block_and_release + 32 11 libdispatch.dylib 0x3dd4 _dispatch_client_callout + 20 12 libdispatch.dylib 0x125a4 _dispatch_main_queue_drain + 988 13 libdispatch.dylib 0x121b8 _dispatch_main_queue_callback_4CF + 44 14 CoreFoundation 0x3751c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16 15 CoreFoundation 0x34218 __CFRunLoopRun + 1996 16 CoreFoundation 0x33968 CFRunLoopRunSpecific + 608 17 GraphicsServices 0x34e0 GSEventRunModal + 164 18 UIKitCore 0x22aedc -[UIApplication _run] + 888 19 UIKitCore 0x22a518 UIApplicationMain + 340 20 MyApp 0xd968 main + 42 (AppDelegate.swift:42) 21 ??? 0x1c8366d84 (Missing) End here is the exception: Crashed: com.apple.main-thread EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000000 This address is always 0x0000000000000000. Anyone having the similar issue?
0
0
531
Mar ’24
layoutAttributesForItem(at indexPath:) never gets called on UICollectionViewLayout subclass
Hi! I've got a custom UICollectionViewLayout which has its cells and two supplementary kind of views scattered all over randomly within its bounds. It should be a calendar month view with day of week labels on top, week numbers on the left (supplementary views) and day cells in the middle (items). So far I tracked down that the layoutAttributesForItem(at indexPath:) and layoutAttributesForSupplementaryView(ofKind elementKind:, at indexPath:) are not getting called. Which gives them a reason not to be placed where they should be. layoutAttributesForElements(in rect: ) gets called indeed and the returned value is also OK: override func layoutAttributesForElements(in rect: CGRect) -&gt; [UICollectionViewLayoutAttributes]? { super.layoutAttributesForElements(in: rect) var arr = [UICollectionViewLayoutAttributes]() arr.append(contentsOf: AllAttributes.filter({ (Item:UICollectionViewLayoutAttributes) -&gt; Bool in (collectionView!.numberOfSections) &gt; Item.indexPath.section &amp;&amp; rect.intersects(Item.frame) })) return arr //47 long array of UICollectionViewLayoutAttributes } In IB the Collection View is specified to be Custom Layout and the respective subclass is specified there. I inspected the official example code here: https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/layouts/customizing_collection_view_layouts The only diffrerence I see is that the example uses UICollectionViewController, which is specified to be Flow Layout in IB, and then the UICollectionView is re-instantiated in code as custom during viewDidLoad. Could that really make a difference? This solution would not be too convenient for me, as I have also other controls on my Controller View. Any help would be appreciated.
0
0
752
Mar ’24
Deinitializer won't get called
I'm presenting a view controller inside a UIAction handler from the new UIButton init configuration API. But when I do it, its deinit won't get called. I'm thinking there's some sort of retain cycle? I've tried capturing [weak self] inside the closure with no success. Using the addTarget method instead, the deinit gets called as expected. What am I doing wrong? let testVC = TestViewController() lazy var testButton: UIButton = { var configuration = UIButton.Configuration.filled() //button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) let button = UIButton(configuration: configuration, primaryAction: UIAction(handler: { action in self.present(testVC, animated: true, completion: nil) })) return button }()
1
0
476
Mar ’24
Can't display the simplest UIToolbar
I thought I could easily display a toolbar in UIKit, but I was wrong, or at least I can't do so without getting "Unable to simultaneously satisfy constraints." console messages. Here is my code: import UIKit class ViewController: UIViewController { let toolbar = UIToolbar() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemBackground toolbar.items = [ UIBarButtonItem(title: "Title", style: .plain, target: nil, action: nil), UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) ] view.addSubview(toolbar) toolbar.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ toolbar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), toolbar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), toolbar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), toolbar.heightAnchor.constraint(equalToConstant: 44) ]) } } And here is the console log: Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSAutoresizingMaskLayoutConstraint:0x600002107b10 h=--& v=--& _UIToolbarContentView:0x104008e40.height == 0 (active)>", "<NSLayoutConstraint:0x600002122e90 V:|-(0)-[_UIButtonBarStackView:0x10250d8b0] (active, names: '|':_UIToolbarContentView:0x104008e40 )>", "<NSLayoutConstraint:0x600002121ef0 _UIButtonBarStackView:0x10250d8b0.bottom == _UIToolbarContentView:0x104008e40.bottom (active)>", "<NSLayoutConstraint:0x600002107a70 UIButtonLabel:0x10250f280.centerY == _UIModernBarButton:0x1027059c0'Title'.centerY + 1.5 (active)>", "<NSLayoutConstraint:0x60000210ea30 'TB_Baseline_Baseline' _UIModernBarButton:0x1027059c0'Title'.lastBaseline == UILayoutGuide:0x600003b0ca80'UIViewLayoutMarginsGuide'.bottom (active)>", "<NSLayoutConstraint:0x60000210ea80 'TB_Top_Top' V:|-(>=0)-[_UIModernBarButton:0x1027059c0'Title'] (active, names: '|':_UIButtonBarButton:0x102607120 )>", "<NSLayoutConstraint:0x60000210e8f0 'UIButtonBar.maximumAlignmentSize' _UIButtonBarButton:0x102607120.height == UILayoutGuide:0x600003b00380'UIViewLayoutMarginsGuide'.height (active)>", "<NSLayoutConstraint:0x60000212c960 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600003b00380'UIViewLayoutMarginsGuide']-(0)-| (active, names: '|':_UIButtonBarStackView:0x10250d8b0 )>", "<NSLayoutConstraint:0x60000210ec60 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x600003b0ca80'UIViewLayoutMarginsGuide']-(11)-| (active, names: '|':_UIButtonBarButton:0x102607120 )>", "<NSLayoutConstraint:0x60000212d6d0 'UIView-topMargin-guide-constraint' V:|-(0)-[UILayoutGuide:0x600003b00380'UIViewLayoutMarginsGuide'] (active, names: '|':_UIButtonBarStackView:0x10250d8b0 )>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x600002107a70 UIButtonLabel:0x10250f280.centerY == _UIModernBarButton:0x1027059c0'Title'.centerY + 1.5 (active)> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSAutoresizingMaskLayoutConstraint:0x600002106710 h=--& v=--& _UIToolbarContentView:0x104008e40.width == 0 (active)>", "<NSLayoutConstraint:0x600002120b40 H:|-(0)-[_UIButtonBarStackView:0x10250d8b0] (active, names: '|':_UIToolbarContentView:0x104008e40 )>", "<NSLayoutConstraint:0x600002122e40 H:[_UIButtonBarStackView:0x10250d8b0]-(0)-| (active, names: '|':_UIToolbarContentView:0x104008e40 )>", "<NSLayoutConstraint:0x60000210eda0 'TB_Leading_Leading' H:|-(16)-[_UIModernBarButton:0x1027059c0'Title'] (active, names: '|':_UIButtonBarButton:0x102607120 )>", "<NSLayoutConstraint:0x60000210eb70 'TB_Trailing_Trailing' H:[_UIModernBarButton:0x1027059c0'Title']-(16)-| (active, names: '|':_UIButtonBarButton:0x102607120 )>", "<NSLayoutConstraint:0x60000210e580 'UISV-canvas-connection' UILayoutGuide:0x600003b00380'UIViewLayoutMarginsGuide'.leading == _UIButtonBarButton:0x102607120.leading (active)>", "<NSLayoutConstraint:0x60000210e5d0 'UISV-canvas-connection' UILayoutGuide:0x600003b00380'UIViewLayoutMarginsGuide'.trailing == UIView:0x10400e480.trailing (active)>", "<NSLayoutConstraint:0x60000210e9e0 'UISV-spacing' H:[_UIButtonBarButton:0x102607120]-(0)-[UIView:0x10400e480] (active)>", "<NSLayoutConstraint:0x60000212c820 'UIView-leftMargin-guide-constraint' H:|-(0)-[UILayoutGuide:0x600003b00380'UIViewLayoutMarginsGuide'](LTR) (active, names: '|':_UIButtonBarStackView:0x10250d8b0 )>", "<NSLayoutConstraint:0x60000212ca00 'UIView-rightMargin-guide-constraint' H:[UILayoutGuide:0x600003b00380'UIViewLayoutMarginsGuide']-(0)-|(LTR) (active, names: '|':_UIButtonBarStackView:0x10250d8b0 )>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x60000210eb70 'TB_Trailing_Trailing' H:[_UIModernBarButton:0x1027059c0'Title']-(16)-| (active, names: '|':_UIButtonBarButton:0x102607120 )> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful. I tried giving the toolbar a frame rather than constraints, and also to not give it an explicit height. The only thing that works is to comment out UIBarButtonItem(title: "Title", style: .plain, target: nil, action: nil), which isn't really a solution. What am I doing wrong?
1
0
549
Mar ’24
Custom UICompositionalLayout wrong UICollectionViewLayoutAttributes
I am subclassing a UICollectionViewCompositionalLayout, for the purpose of adding custom margins to a decoration view. On vertical layouts it works as expected, however when a section with orthogonal scrolling is introduced, UICollectionViewLayoutAttributes that do not pass through layoutAttributesForElements get applied to the DecorationView and thus breaking the layout during scroll. I suspect the OrthogonalScrollViews apply their own attributes incorrectly thus breaking this code. FeedbackID: FB13705625 final class CompositionalViewLayout: UICollectionViewCompositionalLayout { private var decorationViewAttributes: [IndexPath: BackgroundDecoratorLayoutAttributes] = [:] override func prepare() { super.prepare() guard let collectionView = collectionView else { return } decorationViewAttributes.removeAll() for sectionIndex in 0..<collectionView.numberOfSections { let numberOfItems = collectionView.numberOfItems(inSection: sectionIndex) guard numberOfItems > 0, let firstItem = layoutAttributesForItem(at: IndexPath(item: 0, section: sectionIndex)), let lastItem = layoutAttributesForItem( at: IndexPath(item: numberOfItems - 1, section: sectionIndex) ) else { continue } let indexPath = IndexPath(item: 0, section: sectionIndex) // Create section frame var sectionFrame = firstItem.frame.union(lastItem.frame) sectionFrame.size.width = collectionView.frame.width sectionFrame.origin.x = 12 sectionFrame.size.width -= 24 createSectionDecorationView( sectionFrame: sectionFrame, indexPath: indexPath ) } } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { let attributes: [UICollectionViewLayoutAttributes] = super.layoutAttributesForElements(in: rect) ?? [] print("Dinesh :: super Attributes \(attributes)") var modifiedAttributes = [UICollectionViewLayoutAttributes]() var addedAttributes = Set<UICollectionViewLayoutAttributes>() for attribute in attributes { if let customAttr = decorationViewAttributes[attribute.indexPath], attribute.representedElementKind == customAttr.representedElementKind { modifiedAttributes.append(customAttr) addedAttributes.insert(customAttr) } else { modifiedAttributes.append(attribute) } } modifiedAttributes.append(contentsOf: decorationViewAttributes.values.filter { return (!addedAttributes.contains($0) && rect.intersects($0.frame)) }) return modifiedAttributes } override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { guard elementKind == ViewController.sectionBackgroundDecorationElementKind, let decorationAttribute = decorationViewAttributes[indexPath] else { return super.layoutAttributesForDecorationView(ofKind: elementKind, at: indexPath) } return decorationAttribute } private func createSectionDecorationView(sectionFrame: CGRect, indexPath: IndexPath) { let attr = BackgroundDecoratorLayoutAttributes( forDecorationViewOfKind: ViewController.sectionBackgroundDecorationElementKind, with: indexPath ) attr.frame = sectionFrame attr.zIndex = -1 attr.cornerRadius = 12 switch indexPath.section { case 0: attr.backgroundColor = .systemRed case 1: attr.backgroundColor = .systemYellow case 2: attr.backgroundColor = .systemBlue case 3: attr.backgroundColor = .systemGreen case 4: attr.backgroundColor = .systemPink default: attr.backgroundColor = .systemGray } // Cache attribute decorationViewAttributes[indexPath] = attr } } class SectionBackgroundDecorationView: UICollectionReusableView { override init(frame: CGRect) { super.init(frame: frame) configure() } required init?(coder: NSCoder) { fatalError("not implemented") } override func layoutSubviews() { super.layoutSubviews() } override func prepareForReuse() { super.prepareForReuse() } override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { super.apply(layoutAttributes) guard let attr = layoutAttributes as? BackgroundDecoratorLayoutAttributes else { return } backgroundColor = attr.backgroundColor layer.cornerRadius = attr.cornerRadius } }
0
0
411
Apr ’24
How do I resize a UICollectionViewListCell containing a UITextView?
This is a simple collection view with compositional layout and diffable data source. It displays one cell, of type UICollectionViewListCell, whose contentView has a text view as a subview. import UIKit class ViewController: UIViewController { var collectionView: UICollectionView! let textView = UITextView() var dataSource: UICollectionViewDiffableDataSource<Section, Int>! enum Section: CaseIterable { case first } override func viewDidLoad() { super.viewDidLoad() configureHierarchy() configureDataSource() } private func configureHierarchy() { collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout()) view.addSubview(collectionView) collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth] textView.delegate = self } func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { [weak self] cell, indexPath, itemIdentifier in guard let self else { return } cell.contentView.addSubview(textView) textView.pinToSuperviewMargins() } dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier) } var snapshot = NSDiffableDataSourceSnapshot<Section, Int>() snapshot.appendSections(Section.allCases) snapshot.appendItems([1], toSection: .first) dataSource.apply(snapshot) } func createLayout() -> UICollectionViewLayout { UICollectionViewCompositionalLayout { section, layoutEnvironment in var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped) return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) } } } extension ViewController: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { // Do something here? } } The pinToSuperviewMargins method sets the top, bottom, leading and trailing constraints of the view on which it's called to its superview's and its translatesAutoResizingMaskIntoConstraints property to false: extension UIView { func pinToSuperviewMargins( top: CGFloat = 0, bottom: CGFloat = 0, leading: CGFloat = 0, trailing: CGFloat = 0, file: StaticString = #file, line: UInt = #line ) { guard let superview = self.superview else { let localFilePath = URL(fileURLWithPath: "\(file)").lastPathComponent print(">> \(#function) failed in file: \(localFilePath), at line: \(line): could not find \(Self.self).superView.") return } self.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ self.topAnchor.constraint(equalTo: superview.topAnchor, constant: top), self.bottomAnchor.constraint(equalTo: superview.bottomAnchor, constant: bottom), self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: leading), self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: trailing), ]) } func pinToSuperviewMargins(constant c: CGFloat = 0, file: StaticString = #file, line: UInt = #line) { self.pinToSuperviewMargins(top: c, bottom: c, leading: c, trailing: c, file: file, line: line) } } I tried calling collectionView.setNeedsLayout() in textViewDidChange(_:) but it doesn't work. I used to accomplish cell resizing with tableView.beginUpdates(); tableView.endUpdates() when dealing with table views.
2
0
1.2k
Apr ’24
How do you get the cursor to appear programmatically in a custom UITextInput with UITextInteraction?
I have created a custom input field by conforming to UITextInput. It is setup to use UITextInteraction. Everything works very well. If the user taps on the custom field, the cursor (provided by UITextInteraction) appears. The user can type, select, move the cursor, etc. But I'm stumped trying to get the cursor to appear automatically. With a normal UITextField or UITextView you simply call becomeFirstResponder(). But doing that with my custom UITextInput does not result in the cursor appearing. It only appears if the user taps on the custom field. I don't know what I'm missing. I don't see any API in UITextInteraction that can be called to say "activate the cursor layer". Does anyone know what steps are required with a custom UITextInput using UITextInteraction to activate the cursor programmatically without the user needing to tap on the custom field?
4
0
1.2k
Apr ’24
OrderedDictionary encode issue
Hi all, Here I want to encode OrderedDictionary to JSON file, I use the JSONEncoder below: let encoder = JSONEncoder() encoder.outputFormatting = [.prettyPrinted, .withoutEscapingSlashes] and I declare variables qwe, asd and zxc: var qwe = OrderedDictionary<String, Int>() qwe["bbb"] = 12 qwe["ccc"] = 13 qwe["ddd"] = 14 qwe["bbc"] = 15 var asd = Dictionary<String, Int>() asd["bbb"] = 1 asd["ccc"] = 3 asd["ddd"] = 4 asd["bbc"] = 5 var zxc: KeyValuePairs<String, String> { return [ "zz": "zz", "aa": "aa", "bb": "bb", "cc": "cc", "bc": "bc", ] } After I do try encoder.encode(qwe).write(to: path ,options: .atomic) encoder.encode(asd).write(to: path ,options: .atomic) encoder.encode(zxc).write(to: path ,options: .atomic) the output JSON file format of OrderedDictionary isn't what I expected. The output JSON of OrderDictionary is like this: [ "bbb", 12, "ccc", 13, "ddd", 14, "bbc", 15 ] On the other hand, the output JSON of Dictionary and KeyValuePairs are normal, just with different order: Dictonary: { "ccc" : 3, "bbb" : 1, "bbc" : 5, "ddd" : 4 } KeyValuePairs: { "cc" : "cc", "aa" : "aa", "zz" : "zz", "bb" : "bb", "bc" : "bc" } I also Log these objects after I declare them, the Log show their structure are similar: qwe -> ["bbb": 12, "ccc": 13, "ddd": 14, "bbc": 15] asd -> ["ccc": 3, "bbb": 1, "bbc": 5, "ddd": 4] zxc -> ["zz": "zz", "aa": A"aa", "bb": "bb", "cc": "cc", "bc": "bc"] I thought the OrderedDictionary is similar to Dictionary, but does anyone know why the output of OrderedDictionary is not like this: {"bbb": 12, "ccc": 13, "ddd": 14, "bbc": 15} Or is there any other way I can customize the order of keys in my encoded JSON file? Thank you so much!
1
0
473
Apr ’24
Update collection view supplementary view content
If you run the following UIKit app and tap the view controller's right bar button item, the footerText property will change. How should I update the collection view's footer to display the updated footerText? class ViewController: UIViewController { var collectionView: UICollectionView! var footerText = "Initial footer text" var dataSource: UICollectionViewDiffableDataSource<Section, String>! var snapshot: NSDiffableDataSourceSnapshot<Section, String> { var snapshot = NSDiffableDataSourceSnapshot<Section, String>() snapshot.appendSections(Section.allCases) snapshot.appendItems(["A", "a"], toSection: .first) return snapshot } enum Section: CaseIterable { case first } override func viewDidLoad() { super.viewDidLoad() configureHierarchy() configureDataSource() } func configureHierarchy() { navigationItem.rightBarButtonItem = .init(title: "Change footer text", style: .plain, target: self, action: #selector(changeFooterText)) collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout()) view.addSubview(collectionView) collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth] } @objc func changeFooterText() { footerText = "Secondary footer text" } func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in var contentConfiguration = UIListContentConfiguration.cell() contentConfiguration.text = itemIdentifier cell.contentConfiguration = contentConfiguration } dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier) } configureSupplementaryViewProvider() dataSource.apply(self.snapshot) } func configureSupplementaryViewProvider() { let headerRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { headerView, elementKind, indexPath in var contentConfiguration = UIListContentConfiguration.cell() contentConfiguration.text = "Header \(indexPath.section)" headerView.contentConfiguration = contentConfiguration } let footerRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionFooter) { [weak self] headerView, elementKind, indexPath in guard let self else { return } var contentConfiguration = UIListContentConfiguration.cell() contentConfiguration.text = self.footerText headerView.contentConfiguration = contentConfiguration } dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in if kind == UICollectionView.elementKindSectionHeader { collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath) } else if kind == UICollectionView.elementKindSectionFooter { collectionView.dequeueConfiguredReusableSupplementary(using: footerRegistration, for: indexPath) } else { nil } } } func createLayout() -> UICollectionViewLayout { UICollectionViewCompositionalLayout { section, layoutEnvironment in var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped) config.headerMode = .supplementary config.footerMode = .supplementary return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment) } } } What I've tried to do in footerText's didSet: Reconfiguring the supplementary view provider: var footerText = "Initial footer text" { didSet { configureSupplementaryViewProvider() } } Also re-applying the snapshot: var footerText = "Initial footer text" { didSet { configureSupplementaryViewProvider() dataSource.apply(self.snapshot) } } Also re-configuring the items: var footerText = "Initial footer text" { didSet { configureSupplementaryViewProvider() dataSource.apply(self.snapshot, animatingDifferences: true) var snapshot = dataSource.snapshot() snapshot.reconfigureItems(snapshot.itemIdentifiers) dataSource.apply(snapshot, animatingDifferences: false) } }
1
0
906
Apr ’24
Rotate PDF Annotation
I'm working with PDFKit and trying to rotate PDFAnnotation from a PDFView: Here is my code for a normal case(no rotated): class ImageAnnotation: PDFAnnotation { var image: UIImage? init(image: UIImage?, bounds: CGRect) { self.image = image super.init(bounds: bounds, forType: .stamp, withProperties: nil) } override func draw(with box: PDFDisplayBox, in context: CGContext) { guard let cgImage = self.image?.cgImage else { return } context.draw(cgImage, in: bound) } } And here is the way I used to rotate PDFAnnotation: init(image: UIImage?, bounds: CGRect) { self.image = image super.init(bounds: bounds.applying(CGAffineTransform(rotationAngle: -CGFloat.pi/12)), forType: .stamp, withProperties: nil) } override func draw(with box: PDFDisplayBox, in context: CGContext) { guard let cgImage = self.image?.cgImage else { return } context.rotate(by: CGFloat.pi/12) context.draw(cgImage, in: bounds) } But it doesn't work as expected. Can you help me? Thank you.
0
0
529
Apr ’24
USSD calls with * and # dont work iOS
I have an application that needs to make a USSD call, but on some devices the * and # don't work on the dialer, on others it does. if let phoneNumber = ussdNumberTextfield.text { let encoded = "telprompt:\(phoneNumber)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! if let url = URL(string: encoded) { if application.canOpenURL(url){ DispatchQueue.main.async { self.application.open(url, options: [:]) { success in } } } } }
3
0
940
Apr ’24
Syncing UITabBarController selected item state inside of webwrapper -- highlight tab item after webViewBack
I am trying to sync up the selected tab bar item once a user presses back and navigates back in the web wrapper iOS app. Here is how the app works: When a user logs in, they are presented with the Home Screen. To navigate, the select a tab item on the tab bar. This tells webkit to redirect to that URL and then that webpage is shown in the app (wrapped). A back button also appears. When a user presses the back button, the webView.goBack() method sends the user back on in the webView.backForwardList. What happens then is that the user is now on the previous page, however the tab bar has not updated. In other words, the user is back on the first tab but the second tab is highlighted. I tried fixing this by telling the tab bar controller what item to select, however this creates a state malfunction because it also tells the webView to navigate to that url again, so in fact this means that the user isn't going back through web history, but actually is going forward while simulating going back. I need to be able to highlight the tab bar items that sync up with the page that we have gone back to without selecting it. Does anyone have an idea for how to manually highlight or select a tab bar item without actually navigating to that tab bar item? Thank you!
0
0
425
Apr ’24
Non-main thread crash _AssertAutoLayoutOnAllowedThreadsOnly
This crash happens online and cannot be tested and reproduced. I need help. Thank you very much. Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000018b4190d0 Exception Note: EXC_CORPSE_NOTIFY Termination Reason: SIGNAL 5 Trace/BPT trap: 5 Terminating Process: exc handler [338] Triggered by Thread: 7 Last Exception Backtrace: 0 CoreFoundation 0x180cd7c60 __exceptionPreprocess + 216 (NSException.m:200) 1 libobjc.A.dylib 0x198507ee4 objc_exception_throw + 56 (objc-exception.mm:565) 2 CoreAutoLayout 0x1987cb000 _AssertAutoLayoutOnAllowedThreadsOnly + 412 (NSISEngine.m:0) 3 CoreAutoLayout 0x1987cdb7c -[NSISEngine withBehaviors:performModifications:] + 32 (NSISEngine.m:1975) 4 UIKitCore 0x1831262fc -[UIView _resetLayoutEngineHostConstraints] + 80 (NSLayoutConstraint_UIKitAdditions.m:1426) 5 UIKitCore 0x1830fc0c0 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2376 (UIView.m:18416) 6 QuartzCore 0x18477c520 CA::Layer::layout_if_needed(CA::Transaction*) + 528 (CALayer.mm:10118) 7 QuartzCore 0x18476f294 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 132 (CALayer.mm:2480) 8 QuartzCore 0x184782cc8 CA::Context::commit_transaction(CA::Transaction*, double, double*) + 464 (CAContextInternal.mm:2612) 9 QuartzCore 0x18478b79c CA::Transaction::commit() + 708 (CATransactionInternal.mm:449) 10 QuartzCore 0x1847dfe04 CA::Transaction::release_thread(void*) + 224 (CATransactionInternal.mm:651) 11 libsystem_pthread.dylib 0x1dc052d90 _pthread_tsd_cleanup + 520 (pthread_tsd.c:388) 12 libsystem_pthread.dylib 0x1dc055c08 _pthread_exit + 80 (pthread.c:1717) 13 libsystem_pthread.dylib 0x1dc05124c _pthread_wqthread_exit + 100 (pthread.c:2559) 14 libsystem_pthread.dylib 0x1dc050e88 _pthread_wqthread + 420 (pthread.c:2593) 15 libsystem_pthread.dylib 0x1dc05092c start_wqthread + 8 (:-1)
1
0
642
Apr ’24