The following is a screenshot of the crash stack. What caused this crash? How to solve it?
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Post
Replies
Boosts
Views
Activity
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)
}
}
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.
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
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?
I can't override the show(_:sender:) of UIViewController or else my app freezes when the method is called (Xcode 15.3 simulator, iOS 17.4, macOS Sonoma 14.3.1, MacBook Air M1 8GB).
Is there any workaround?
override func show(_ vc: UIViewController, sender: Any?) {
super.show(vc, sender: sender)
}
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) -> [UICollectionViewLayoutAttributes]?
{
super.layoutAttributesForElements(in: rect)
var arr = [UICollectionViewLayoutAttributes]()
arr.append(contentsOf: AllAttributes.filter({ (Item:UICollectionViewLayoutAttributes) -> Bool in
(collectionView!.numberOfSections) > Item.indexPath.section &&
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.
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
}()
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?
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
}
}
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.
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?
I am currently working on an iOS application where I want to implement the safari tabs and when I have to minimize that one to check how many numbers of tabs are opened. How can I do this?
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!
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)
}
}
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.
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
}
}
}
}
}
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!
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)
0
I want to get notification like UIApplication.didBecomeActiveNotification and UIApplication.willResignActiveNotification when app switches in iPad Stage Controller Mode, but UIApplication.didBecomeActiveNotification, UIApplication.willResignActiveNotification just dont work, is there any method to get this notification