I'm trying to make a magnifying glass that shows up when the user presses a button and follows the user's finger as it's dragged across the screen.
I came across a UIKit-based solution (https://github.com/niczyja/MagnifyingGlass-Swift), but when implemented in my SKScene, only the crosshairs are shown. Through experimentation I've found that magnifiedView?.layer.render(in: context) in:
public override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
context.translateBy(x: radius, y: radius)
context.scaleBy(x: scale, y: scale)
context.translateBy(x: -magnifiedPoint.x, y: -magnifiedPoint.y)
removeFromSuperview()
magnifiedView?.layer.render(in: context)
magnifiedView?.addSubview(self)
}
can be removed without altering the situation, suggesting that line is not working as it should. But this is where I hit a brick wall. The view below is shown but not offset or magnified, and any attempt to add something to context results in a black magnifying glass.
Does anyone know why this is? I don't think it's an issue with the code, so I'm suspecting its something specific to SpriteKit or SKScene, likely related to how CALayers work.
Any pointers would be greatly appreciated.
.
.
.
Full code below:
import UIKit
public class MagnifyingGlassView: UIView {
public weak var magnifiedView: UIView? = nil {
didSet {
removeFromSuperview()
magnifiedView?.addSubview(self)
}
}
public var magnifiedPoint: CGPoint = .zero {
didSet {
center = .init(x: magnifiedPoint.x + offset.x, y: magnifiedPoint.y + offset.y)
}
}
public var offset: CGPoint = .zero
public var radius: CGFloat = 50 {
didSet {
frame = .init(origin: frame.origin, size: .init(width: radius * 2, height: radius * 2))
layer.cornerRadius = radius
crosshair.path = crosshairPath(for: radius)
}
}
public var scale: CGFloat = 2
public var borderColor: UIColor = .lightGray {
didSet {
layer.borderColor = borderColor.cgColor
}
}
public var borderWidth: CGFloat = 3 {
didSet {
layer.borderWidth = borderWidth
}
}
public var showsCrosshair = true {
didSet {
crosshair.isHidden = !showsCrosshair
}
}
public var crosshairColor: UIColor = .lightGray {
didSet {
crosshair.strokeColor = crosshairColor.cgColor
}
}
public var crosshairWidth: CGFloat = 5 {
didSet {
crosshair.lineWidth = crosshairWidth
}
}
private let crosshair: CAShapeLayer = CAShapeLayer()
public convenience init(offset: CGPoint = .zero, radius: CGFloat = 50, scale: CGFloat = 2, borderColor: UIColor = .lightGray, borderWidth: CGFloat = 3, showsCrosshair: Bool = true, crosshairColor: UIColor = .lightGray, crosshairWidth: CGFloat = 0.5) {
self.init(frame: .zero)
layer.masksToBounds = true
layer.addSublayer(crosshair)
defer {
self.offset = offset
self.radius = radius
self.scale = scale
self.borderColor = borderColor
self.borderWidth = borderWidth
self.showsCrosshair = showsCrosshair
self.crosshairColor = crosshairColor
self.crosshairWidth = crosshairWidth
}
}
public func magnify(at point: CGPoint) {
guard magnifiedView != nil else { return }
magnifiedPoint = point
layer.setNeedsDisplay()
}
private func crosshairPath(for radius: CGFloat) -> CGPath {
let path = CGMutablePath()
path.move(to: .init(x: radius, y: 0))
path.addLine(to: .init(x: radius, y: bounds.height))
path.move(to: .init(x: 0, y: radius))
path.addLine(to: .init(x: bounds.width, y: radius))
return path
}
public override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else { return }
context.translateBy(x: radius, y: radius)
context.scaleBy(x: scale, y: scale)
context.translateBy(x: -magnifiedPoint.x, y: -magnifiedPoint.y)
removeFromSuperview()
magnifiedView?.layer.render(in: context)
//If above disabled, no change
//Possible that nothing's being rendered into context
//Could it be that SKScene view has no layer?
magnifiedView?.addSubview(self)
}
}
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Posts under UIKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Is there a way to make UITextField activate when double-tapped? Single-tapping makes it a little too easy to do something calamitous in my app.
iPhone mirroring is available from macOS 15.
When running an app with iPhone mirroring
Can I know whether the app currently being mirrored is running at the top of the Mac app or screen?
Or is there a way to know whether it is hidden by another app on the Mac or re-displayed?
If not, I hope it will be added in a future update.
And I hope there is an API that can tell whether the current app is connected to iPhone mirroring or not.
iPhone mirroring function has been added to this macOS.
I am also currently using the iPhone mirroring function.
However, when isSelectable is set to true in UITextView and isEditable is set to false
(isScrollEnabled is also set to false.)
Editing is not possible, but selection is possible. (In non-mirroring mode)
But in iPhone mirroring mode, selection is not possible
Is there an option for UITextView that allows text selection or a separate setting in macOS?
Or can this be fixed in the iPhone mirroring app when macOS is updated in the future? (If it is a bug or error?)
It seems to work normally in cases where UITextView is used but Edit is possible, such as in the memo app.
I am making a swift app supporting multi language ,showing proper language ui according user's phone setting language, I want to launch different screen (showing different image, boot-en.jpg, boot-ja.jpg) according language,i created two LaunchScreen files ,LaunchScreen-en.storyboard and LaunchScreen-ja.storyboard and localize them ,and add a different UIImage to them,
then create two InfoPlist.strings file with congfiging
."UILaunchStoryboardName" = "LaunchScreen_en"; //
"UILaunchStoryboardName" = "LaunchScreen_ja";//
and then **config info.plist ** with
UILaunchStoryboardName
LaunchScreen
above all steps ,build and run,hope to see launch screen showing boot-ja.jpg when phone's language is Japanese, showing boot-en.jpg when phone's language is English, but it shows black screen, how to fix this problem, thank you.
I have two views in a container view as below
@IBOutlet weak var dataDisclosureView: UIStackView! // Main ContainerView
@IBOutlet private weak var titleLabel: UILabel! {
didSet {
titleLabel.text = "Hello"
}
}
@IBOutlet private weak var descriptionLabel: UILabel! {
didSet {
descriptionLabel.text = "World"
}
}
@IBOutlet weak var descriptionView: UIStackView! { // sub container view containing titleLabel and descriptionLabel
didSet {
descriptionView.isAccessibilityElement = true
descriptionView.accessibilityLabel = "Hello"
descriptionView.accessibilityIdentifier = "test_hello"
}
}
@IBOutlet private weak var requestButton: UIButton! {
didSet {
requestButton.isAccessibilityElement = true
requestButton.accessibilityLabel = "Request Button"
requestButton.accessibilityIdentifier = "test_button"
}
}
override func viewDidLoad() {
super.viewDidLoad()
dataDisclosureView.isAccessibilityElement = false
dataDisclosureView.accessibilityElements = [ descriptionView ?? "" ]
if #available(iOS 17.0, *) {
dataDisclosureView.automationElements = [ descriptionView ?? "",
requestButton ?? ""]
} else {
// Fallback on earlier versions
}
let requestButtonAction = UIAccessibilityCustomAction(name: "start",
target: self,
selector: #selector( request))
dataDisclosureView.accessibilityCustomActions = [ requestButtonAction ]
}
Mx issue is I want AccessibilityIdentifers for descriptionLabel,titleLabel,requestButton and hintLabel(For Automation) and accessibility labels for descriptionView and requestButton(VoiceOver Accessibility).
But I am unable to see accessibilityIdentifier for Button, TitleLabel and descriptionLabel in AccessibilityInspector. what am I doing wrong here?
I have an image and label inside UIStackView which are inside a viewcontroller. I want to make my UIView accessible. So I wrote below code:
var image: UIImage!
var myView: UIStackView!
var label : UILabel!
myView.isAccessibilityElement = true
myView.accessibilityLabel = "Hello"
myView.accessiblityIdentifier = "test_view"
image.accessiblityIdentifier = "test_image"
label.accessibilityIdentifier = "test_label"
All are UIKit Elements.
How to expose mvView to accessibility and only children to automation
I tried below two ways, none of them worked:
self.view.accessibilityElements = [myView]
myView.accessibilityElements = []
from apple documentation :
If the object is a view and it’s an accessibility element, and accessibilityElements is empty, the system assigns the list of subviews that have an accessibilityIdentifier to automationElements.
myView.automationElements = [myView,image,label]
from apple documentation :
In some cases, you might want to expose elements for automation but not for accessibility, or vice versa. In a view containing an image with a label under it, for example, you might choose to expose only the label for accessibility. For automation, however, you might include both the image and the label in a test to confirm the both objects exist. In this case, add both the image and the label to automationElements.
I am really going crazy with this since many days. Help is very much appreciated.
Our application has seen a surge in the volume of background launches starting from April and May, and we want to know under what circumstances the application can be launched from the background.
First, here's how I determined background launches: we analyze user logs and append UIApplication.appState to each line of log, finding that every log from the start to the end of user sessions has an appState of UIApplicationStateBackground.
By checking the "ActivePrewarm" in main() and printing the launch options from application:didFinishLaunchingWithOptions:, we found several scenarios for background launches:
launchOptions has a value with the key UIApplicationLaunchOptionsRemoteNotificationKey.
launchOptions has no value and there is no "ActivePrewarm."
launchOptions has no value but has "ActivePrewarm."
I would like to know:
Under what circumstances will notifications trigger a background launch (I cannot replicate this locally)?
Under what circumstances does an application launch in the background and trigger application:didFinishLaunchingWithOptions: but without any launch options?
I hope informations below can provide some insights.
Regarding "ActivePrewarm," I've read various questions and answers in the Apple Developer Forums, such as this thread, which states that "ActivePrewarm" does not trigger application:didFinishLaunchingWithOptions: but occurs due to certain behaviors in the application. I would like to know what behaviors may cause this background launch, as there is no information in the launch options, or how I can identify what behaviors triggered it.
Specifically, based on that same thread, I've tried to gather more information using runningboardd, and I've currently identified two special cases:
When I restart my phone and unlock it after a short period, there is information:
<RBSDomainAttribute| domain:"com.apple.dasd" name:"DYLDLaunch" sourceEnvironment:"(null)">
]>
Every day, at intervals of a few hours, there is information:
<RBSDomainAttribute| domain:"com.apple.dasd" name:"DYLDLaunch" sourceEnvironment:"(null)">
]>
Then, the following similar information follows:
12:15:56.047625+0800 runningboardd Executing launch request for app<{my_bundle_id}((null))> (DAS Prewarm launch)
12:15:56.050311+0800 runningboardd Creating and launching job for: app<{my_bundle_id}((null))>
12:15:56.050333+0800 runningboardd _mutateContextIfNeeded called for {my_bundle_id}
12:15:56.080560+0800 runningboardd app<{my_bundle_id}((null))>: -[RBPersonaManager personaForIdentity:context:personaUID:personaUniqueString:] required 0.000954 ms (wallclock); resolved to {1000, 39E408CF-2E67-4DB0-BF73-CFC5792285CD}
12:15:56.080632+0800 runningboardd 'app<{my_bundle_id}(39E408CF-2E67-4DB0-BF73-CFC5792285CD)>' Skipping container path lookup because containerization was prevented (<RBSLaunchContext: 0xcd8cc9180>)
12:15:56.080939+0800 runningboardd 'app<{my_bundle_id}(39E408CF-2E67-4DB0-BF73-CFC5792285CD)>' Constructed job description:
<dictionary: 0xcd8aa2a00> { count = 19, transaction: 0, voucher = 0x0, contents = *** }
12:15:56.084839+0800 runningboardd [app<{my_bundle_id}((null))>:1649] Memory Limits: active 4096 inactive 4096
<private>
12:15:56.084861+0800 runningboardd [app<{my_bundle_id}((null))>:1649] This process will be managed.
12:15:56.084882+0800 runningboardd Now tracking process: [app<{my_bundle_id}((null))>:1649]
12:15:56.084928+0800 runningboardd Calculated state for app<{my_bundle_id}((null))>: running-active (role: Background) (endowments: (null))
12:15:56.086762+0800 runningboardd Using default underlying assertion for app: [app<{my_bundle_id}((null))>:1649]
12:15:56.086977+0800 runningboardd Acquiring assertion targeting [app<{my_bundle_id}((null))>:1649] from originator [app<{my_bundle_id}((null))>:1649] with description <RBSAssertionDescriptor| "RB Underlying Assertion" ID:33-33-23101 target:1649 attributes:[
<RBSDomainAttribute| domain:"com.apple.underlying" name:"defaultUnderlyingAppAssertion" sourceEnvironment:"(null)">,
<RBSAcquisitionCompletionAttribute| policy:AfterApplication>
]>
12:15:56.087203+0800 runningboardd Assertion 33-33-23101 (target:[app<{my_bundle_id}((null))>:1649]) will be created as active
12:15:56.087946+0800 runningboardd [app<{my_bundle_id}((null))>:1649] reported to RB as running
12:15:56.088053+0800 runningboardd Calculated state for app<{my_bundle_id}((null))>: running-active (role: Background) (endowments: (null))
12:15:56.088114+0800 runningboardd [app<{my_bundle_id}((null))>:1649] Set jetsam priority to 0 [0] flag[1]
12:15:56.088136+0800 runningboardd [app<{my_bundle_id}((null))>:1649] Resuming task.
12:15:56.088211+0800 runningboardd [app<{my_bundle_id}((null))>:1649] Set darwin role to: Background
12:15:56.088449+0800 runningboardd [app<{my_bundle_id}((null))>:1649] set Memory Limits to Hard Inactive (4096)
12:15:56.089314+0800 runningboardd Successfully acquired underlying assertion for [app<{my_bundle_id}((null))>:1649]
12:15:56.589755+0800 runningboardd Invalidating assertion 33-76-23100 (target:app<{my_bundle_id}((null))>) from originator [osservice<com.apple.dasd>:76]
12:15:56.590332+0800 runningboardd Removed last relative-start-date-defining assertion for process app<{my_bundle_id}((null))>
12:15:56.593760+0800 runningboardd [app<{my_bundle_id}((null))>:1649] Suspending task.
12:15:56.594120+0800 runningboardd Calculated state for app<{my_bundle_id}((null))>: running-suspended (role: None) (endowments: (null))
From these logs, I understand that the system is accelerating the launch speed of the application.
But the time interval between these two logs below is very short, which suggests that the prewarm is executed just before main, and then the process is suspended. Is this understanding correct?
12:15:56.089314+0800 runningboardd Successfully acquired underlying assertion ...
12:15:56.589755+0800 runningboardd Invalidating assertion ...
Regarding "DAS DYLD3 Closure Generation," I speculate that after a user restarts their phone, the system uses DYLD3 to prepare closures for frequently used applications, allowing for faster application launches. Is this assumption correct?
The interactiveDismissDisabled() function in SwiftUI's Sheet no longer works as expected in iOS 18.1 (22B83). It was working as expected until iOS 18.0.1. Are there any other users experiencing the same issue?
struct ContentView: View {
@State private var openSheet = false
var body: some View {
NavigationStack {
Button("Open") {
openSheet = true
}
.sheet(isPresented: $openSheet) {
SheetView()
}
}
}
}
struct SheetView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
NavigationStack {
Text("This is the Sheet")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { dismiss() }
}
}
.interactiveDismissDisabled()
}
}
}
Supplementary information: In iOS 18.1, even Apple's native Journal app allows users to swipe-to-dismiss the sheet when creating a new entry. Previously, a confirmation dialog would be displayed, but this is no longer the case.
Hi All
I faced up with strange issue in my app.
Everything works in iOS 18.0 and lower.
But after install iOS 18.1 same app from App Store crashes every time with error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Storyboard (<UIStoryboard: 0x11f6287a0>) doesn't contain a view controller with identifier 'MKCPinEntryViewControllerIdentifier''
Interesting that this view controller exist in the Storyboard.
First call in app:
dispatch_async(dispatch_get_main_queue(), ^{
//No authentication, needs login view controller popped.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
PinEntryViewController *pinViewController = [storyboard instantiateViewControllerWithIdentifier:@"PinEntryViewControllerIdentifier"];
pinViewController.delegate = self;
pinViewController.entryType = PinEntryTypeEnter;
[self.presentationContext presentViewController:pinViewController animated:YES completion:nil];
});
works good.
But second call in other place after 5 seconds:
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
PinEntryViewController *pinViewController = [storyboard instantiateViewControllerWithIdentifier:@"PinEntryViewControllerIdentifier"];
pinViewController.delegate = self;
[self.presentationContext presentViewController:pinViewController animated:YES completion:nil];
});
crash the app with
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Storyboard (<UIStoryboard: 0x11f6287a0>) doesn't contain a view controller with identifier 'MKCPinEntryViewControllerIdentifier''
*** First throw call stack:
(0x1841b47cc 0x1814872e4 0x186d9c140 0x1063d692c 0x10301ec08 0x104370a30 0x10437271c 0x104382de8 0x1043829a4 0x184188204 0x184185440 0x184184830 0x1d01641c4 0x186ceaeb0 0x186d995b4 0x10667fe3c 0x1a9b72ec8)
libc++abi: terminating due to uncaught exception of type NSException
And issue not only with this view controller.
issue with all in that storyboard.
At start up instantiateViewControllerWithIdentifier works good with all view controllers identifiers. But on second call in other places in the app - all crash with same error
Reproduce in real device with iOS18.1 only. Simulators and devices with iOS 18.0 works well.
Could someone help me, what's wrong with the app?
I'm trying to use a SwiftUI view as UICalendarView decoration and I get Call to main actor-isolated instance method 'makeContentView()' in a synchronous nonisolated context; this is an error in the Swift 6 language mode in the following code:
class Coordinator: NSObject, UICalendarViewDelegate {
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
.customView {
UIHostingConfiguration {
...
}
.makeContentView()
}
}
}
I've fixed using MainActor.assumeIsolated but is this the correct approach or is there a better one?
class Coordinator: NSObject, UICalendarViewDelegate {
func calendarView(_ calendarView: UICalendarView, decorationFor dateComponents: DateComponents) -> UICalendarView.Decoration? {
.customView {
MainActor.assumeIsolated {
UIHostingConfiguration {
...
}
.makeContentView()
}
}
}
}
Our application uses UIActivityViewController to share files, and we have received numerous complaints from users stating that triggering the share functionality causes the app to hang, making it unresponsive. Users are instructed to restart their devices, after which the sharing function works normally.
0 libsystem_kernel.dylib 0x00000001daae2708 mach_msg2_trap + 8
1 libsystem_kernel.dylib 0x00000001daae5e18 mach_msg2_internal + 80
2 libsystem_kernel.dylib 0x00000001daae5d30 mach_msg_overwrite + 424
3 libsystem_kernel.dylib 0x00000001daae5b7c mach_msg + 24
4 libdispatch.dylib 0x00000001926d1f14 _dispatch_mach_send_and_wait_for_reply + 544
5 libdispatch.dylib 0x00000001926d22b4 dispatch_mach_send_with_result_and_wait_for_reply + 60
6 libxpc.dylib 0x0000000211c1b84c xpc_connection_send_message_with_reply_sync + 256
7 Foundation 0x00000001891e98d8 __NSXPCCONNECTION_IS_WAITING_FOR_A_SYNCHRONOUS_REPLY__ + 16
8 Foundation 0x00000001891e6034 -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 2160
9 Foundation 0x000000018924fda4 -[NSXPCConnection _sendSelector:withProxy:arg1:] + 116
10 Foundation 0x000000018924fa18 _NSXPCDistantObjectSimpleMessageSend1 + 60
11 ShareSheet 0x00000001a89e7b2c -[SFShareSheetSlotManager ensureConnectionEstablished] + 220
12 ShareSheet 0x00000001a89e7960 -[SFShareSheetSlotManager ensureXPCStarted] + 440
13 ShareSheet 0x00000001a89e7f90 -[SFShareSheetSlotManager activate] + 188
14 ShareSheet 0x00000001a8a0020c -[SHSheetServiceManager init] + 100
15 ShareSheet 0x00000001a89f347c -[SHSheetInteractor _setupServiceManagerIfNeeded] + 52
16 ShareSheet 0x00000001a89f1998 -[SHSheetInteractor initWithContext:] + 76
17 ShareSheet 0x00000001a89dd450 +[SHSheetFactory createMainPresenterWithContext:] + 204
18 ShareSheet 0x00000001a89d3e90 -[UIActivityViewController _createMainPresenterIfNeeded] + 84
19 ShareSheet 0x00000001a89d53c4 -[UIActivityViewController _viewControllerPresentationDidInitiate] + 104
20 UIKitCore 0x000000018d247fd0 -[UIViewController _presentViewController:withAnimationController:completion:] + 220
21 UIKitCore 0x000000018d24a71c __63-[UIViewController _presentViewController:animated:completion:]_block_invoke + 88
22 UIKitCore 0x000000018d244ad0 -[UIViewController _performCoordinatedPresentOrDismiss:animated:] + 532
23 UIKitCore 0x000000018d2447c0 -[UIViewController _presentViewController:animated:completion:] + 324
24 UIKitCore 0x000000018d2445cc -[UIViewController presentViewController:animated:completion:] + 164
Above is the stack trace when the hang occurs. We found that UIActivityViewController ultimately calls xpc_connection_send_message_with_reply_sync, which synchronously waits for messages on the main thread, leading to the hang.
Are there any suggestions that can avoid this waiting forever hang?
I belong to an EC shop application developers' team, and we got a crame from a small part of our customers about our application.
"Search Bar does not work on iOS 18."
This bug doesn't appear on most of our devices updated to iOS 18.0.
In some cases, it disappeared by turning [Settings > Accessibility > Touch > Reachability] off.
But it is not the same for all customers found the bug.
I'm looking for how to fix this bug, and why it happens.
I'm not sure but I doubt that this may be a bug of iOS18, UIKit, RxCocoa, RxSwift, or something else.
Any information would be welcome.
import UIKit
import RxSwift
import RxCocoa
@IBDesignable
public final class SearchBar: UISearchBar {
var textField: UITextField {
if #available(iOS 13.0, *) {
return searchTextField
} else {
return value(forKey: "_searchField") as! UITextField
}
}
private let disposeBag = DisposeBag()
private func bind() {
textField.rx.isFirstResponder
.bind(to: Binder(self) { me, isFirstResponder in
// This doesn't work in some iOS 18 devices.
me.textField.attributedPlaceholder = placeholderAttributedString(isFirstResponder: isFirstResponder)
me.textField.backgroundColor = isFirstResponder ? Asset.Colors.whiteTwo.color : .white
if me.useCancelButton {
me.showsCancelButton = isFirstResponder
}
if me.useBookmarkButton {
me.showsBookmarkButton = !isFirstResponder
}
})
.disposed(by: disposeBag)
}
public override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
public override func awakeFromNib() {
super.awakeFromNib()
commonInit()
}
public override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
commonInit()
}
private func commonInit() {
bind()
}
}
extension Reactive where Base: SearchBar {}
import UIKit
import RxSwift
import RxCocoa
@IBDesignable
public final class SearchHeaderView: UIView {
@IBOutlet private weak var searchBar: SearchBar!
@IBOutlet private weak var cartContainerView: UIView!
private let disposeBag = DisposeBag()
public override init(frame: CGRect) {
super.init(frame: frame)
loadFromNib()
commonInit()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
public override func awakeFromNib() {
super.awakeFromNib()
loadFromNib()
commonInit()
}
public override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
loadFromNib()
commonInit()
}
private func commonInit() {
bind()
}
private func bind() {
// ↓ This doesn't work in some iOS 18 devices.
searchBar.textField.rx.isFirstResponder
.bind(to: cartContainerView.rx.isHidden)
.disposed(by: disposeBag)
}
}
extension SearchAndCartHeaderView: NibOwnerLoadable {}
I need a magnifying glass function for one of my SwiftUI Views, but can't find a way to implement it as needed.
I found a Youtube video where the author renders the view twice, overlaying the second over the first, then scaling and masking it to create the illusion of magnification, but this is expensive and doesn't work in many cases where more complex views are presented (e.g. a LazyVGrid).
I've also explored continually capturing partial screenshots and scaling them up to create the illusion of magnification, but there's no straightforward way to achieve this with SwiftUI without getting into the messiness of UIViewRepresentables.
Any help would be greatly appreciated
In visionOS, i have been trying to implement this view as a background for information view, but i cannot find any information about it anywhere. Does anyone know what this is called or any workaround to achieve this look?
let activityViewController = UIActivityViewController(activityItems: items,
applicationActivities: [])
activityViewController.popoverPresentationController?.barButtonItem = navigationController.topViewController?.navigationItem.rightBarButtonItem
navigationController.present(activityViewController, animated: true, completion: nil)
Crash logs
=====================================================
*** Assertion failure in -[_UIActivityContentCollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewCategory:], UICollectionView.m:7588
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempted to dequeue a cell for a different registration or reuse identifier than the existing cell when reconfiguring an item, which is not allowed. You must dequeue a cell using the same registration or reuse identifier that was used to dequeue the cell originally to obtain the existing cell. Dequeued reuse identifier: UIActivityContentActionCellIdentifier; Original reuse identifier: UIActivityActionGroupCell; Existing cell: <UIActivityActionGroupCell: 0x10f19f220; baseClass = _UICollectionViewListCell; frame = (16 354; 358 30); clipsToBounds = YES; layer = <CALayer: 0x600000781740>>'
The Maps app on macOS always zooms the same way (two fingers up to zoom in, two fingers down to zoom out) when the shift key is held down, regardless of whether natural scrolling is turned off. I'd like to replicate this same behavior using UIPanGestureRecognizer, but the translation is always inverted whenever I disable natural scrolling. How can I detect if natural scrolling is enabled or disabled when the pan gesture is detected?
For a UIKit app based on scenes (UIScene), is it safe to reference UserDefaults in code that is executed from UIApplicationDelegate/application(_: didFinishLaunchingWithOptions:) ?
I've read that in iOS 15, there were undocumented scenarios involving app prewarming that would cause UserDefaults reads to fail within a window of time after device reboots, as described at https://christianselig.com/2024/10/beware-userdefaults/
The failure mode is that an app would be released, and months later, a small fraction of users would report failures consistent with UserDefaults reads unexpectedly returning nil, causing a loss of data. The user experience is bad, and debugging this behavior is then challenging because of how rarely it occurs.
Apple's https://developer.apple.com/documentation/uikit/app_and_environment/responding_to_the_launch_of_your_app/about_the_app_launch_sequence#3894431 seems to suggest that prewarming only executes an app "up until, but not including when main() calls UIApplicationMain(_:_:_:_:), but https://stackoverflow.com/questions/71025205/ios-15-prewarming-causing-appwilllaunch-method-when-prewarm-is-done documents that UIApplicationDelegate/application(_: didFinishLaunchingWithOptions:) has in fact been observed executing during app prewarming in scene-based apps.
So, my question: In an app based on scenes, if I'd like to reference UserDefaults within UIApplicationDelegate/application(_: didFinishLaunchingWithOptions:), when is it safe to do this?
I'm guessing the answer is one of these:
Never.
Only in apps that don't support scenes.
Only in iOS 16 or later.
Only in IOS 17 or later.
Is it guaranteed safe to reference UserDefaults in UIWindowSceneDelegate/scene(_:willConnectTo:options:) or later?
Is there documentation from Apple regarding this issue?
Thank you.
I've got a UIKit app with a collapsible trailing-edge child view controller, implemented sort of like UISplitViewController but it's got a bunch of custom behavior - moving to the bottom edge in portrait orientation, etc. It exposes a couple of different app functions via a UITabBar on the bottom edge on iOS.
When I run the app on visionOS, that tab bar transforms to a leading-edge ornament. This would be great, but that means it tries to overlap the trailing-edge content of its parent view controller, which isn't ideal.
Is there a way to get the tab bar to lay out on the trailling edge of the child view controller? Or can I create a custom ornament that has the same auto-expand behavior as the tab bar, where it shows a vertical column of icons that expands to show titles when you're gazing at it?
I have a record button that either starts or stops a recording using the default action. When the user is recording, I want to add a custom action to discard the recording instead of saving it. That all works fine with the following code:
if isRecording {
recordButton.accessibilityCustomActions = [
.init(name: String(localized: "discard recording"), actionHandler: { [weak delegate] _ in
delegate?.discardRecording()
return true
})
]
recordButton.accessibilityLabel = String(localized: "stop recording", comment: "accessibility label")
} else {
recordButton.accessibilityCustomActions = []
recordButton.accessibilityLabel = String(localized: "start recording", comment: "accessibility label")
}
The problem I have is that when a user chose "discard recording", it becomes the default selected action again the next time the user records, and instead of stopping and saving the recording, the user might accidentally discard the next one as well.
How can I programmatically reset the selected action on this recordButton to the default action?