In a UIKit application, removing a view from the hierarchy is straightforward—we simply call myView.removeFromSuperview(). This not only removes myView from the UI but also deallocates any associated memory.
Now that I'm transitioning to SwiftUI, I'm struggling to understand the recommended way to remove a view from the hierarchy, given SwiftUI's declarative nature.
I understand that in SwiftUI, we declare everything that should be displayed. However, once a view is rendered, what is the correct way to remove it? Should all UI elements be conditionally controlled to determine whether they appear or not?
Below is an example of how I’m currently handling this, but it doesn’t feel like the right approach for dynamically removing a view at runtime.
Can someone guide me on the best way to remove views in SwiftUI?
struct ContentView: View {
@State private var isVisible = true
var body: some View {
VStack {
if isVisible { // set this to false to remove TextView?
Text("Hello, SwiftUI!")
.padding()
}
Button("Toggle View") {
...
}
}
}
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I'm working on an iOS app that requires an @mention system in a UITextView, similar to those in apps like Twitter or Slack. Specifically, I need to:
Detect @ Symbol and Show Dropdown: When the user types "@", display a dropdown (UITableView or similar) below the cursor with a list of mentionable users, filtered as the user types.
Handle Selection: Insert the selected username as a styled mention (e.g., blue text).
Smart Backspace Behavior: Ensure backspace deletes an entire mention as a single unit when the cursor is at its end, and cancels the mention process if "@" is deleted.
I've implemented a solution using UITextViewDelegate textViewDidChange(_:) to detect "@", a UITableView for the dropdown, and NSAttributedString for styling mentions. For smart backspace, I track mention ranges and handle deletions accordingly. However, I’d like to know:
What is Apple’s recommended approach for implementing this behavior?
Are there any UIKit APIs that simplify this, for proving this experience like smart backspace or custom text interactions?
I’m using Swift/UIKit. Any insights, sample code, or WWDC sessions you’d recommend would be greatly appreciated!
Edit: I am adding the ViewController file to demonstrate the approach that I m using.
import UIKit
// MARK: - Dummy user model
struct MentionUser {
let id: String
let username: String
}
class ViewController: UIViewController, UITextViewDelegate, UITableViewDelegate, UITableViewDataSource {
// MARK: - UI Elements
private let textView = UITextView()
private let mentionTableView = UITableView()
// MARK: - Data
private var allUsers: [MentionUser] = [...]
private var filteredUsers: [MentionUser] = []
private var currentMentionRange: NSRange?
// MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupTextView() // to setup the UI
setupDropdown() // to setup the UI
}
// MARK: - UITextViewDelegate
func textViewDidChange(_ textView: UITextView) {
let cursorPosition = textView.selectedRange.location
let text = (textView.text as NSString).substring(to: cursorPosition)
if let atRange = text.range(of: "@[a-zA-Z0-9_]*$", options: .regularExpression) {
let nsRange = NSRange(atRange, in: text)
let query = (text as NSString).substring(with: nsRange).dropFirst()
currentMentionRange = nsRange
filteredUsers = allUsers.filter {
$0.username.lowercased().hasPrefix(query.lowercased())
}
mentionTableView.reloadData()
showMentionDropdown()
} else {
hideMentionDropdown()
currentMentionRange = nil
}
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text.isEmpty, let attributedText = textView.attributedText {
if range.location == 0 { return true }
let attr = attributedText.attributes(at: range.location - 1, effectiveRange: nil)
if let _ = attr[.mentionUserId] {
let fullRange = (attributedText.string as NSString).rangeOfMentionAt(location: range.location - 1)
let mutable = NSMutableAttributedString(attributedString: attributedText)
mutable.deleteCharacters(in: fullRange)
textView.attributedText = mutable
textView.selectedRange = NSRange(location: fullRange.location, length: 0)
textView.typingAttributes = [
.font: textView.font ?? UIFont.systemFont(ofSize: 16),
.foregroundColor: UIColor.label
]
return false
}
}
return true
}
// MARK: - Dropdown Visibility
private func showMentionDropdown() {
guard let selectedTextRange = textView.selectedTextRange else { return }
mentionTableView.isHidden = false
}
private func hideMentionDropdown() {
mentionTableView.isHidden = true
}
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredUsers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "@\(filteredUsers[indexPath.row].username)"
return cell
}
// MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
insertMention(filteredUsers[indexPath.row])
}
// MARK: - Mention Insertion
private func insertMention(_ user: MentionUser) {
guard let range = currentMentionRange else { return }
let mentionText = "\(user.username)"
let mentionAttributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.systemBlue,
.mentionUserId: user.id
]
let mentionAttrString = NSAttributedString(string: mentionText, attributes: mentionAttributes)
let mutable = NSMutableAttributedString(attributedString: textView.attributedText)
mutable.replaceCharacters(in: range, with: mentionAttrString)
let spaceAttr = NSAttributedString(string: " ", attributes: textView.typingAttributes)
mutable.insert(spaceAttr, at: range.location + mentionText.count)
textView.attributedText = mutable
textView.selectedRange = NSRange(location: range.location + mentionText.count + 1, length: 0)
textView.typingAttributes = [
.font: textView.font ?? UIFont.systemFont(ofSize: 16),
.foregroundColor: UIColor.label
]
hideMentionDropdown()
}
}
// MARK: - Custom Attributed Key
extension NSAttributedString.Key {
static let mentionUserId = NSAttributedString.Key("mentionUserId")
}
I’m working with UIButton and I’d like to register multiple UIControl.Events (e.g. .touchUpInside, .touchDown, .touchCancel, .primaryActionTriggered) using the same selector.
For example:
button.addTarget(self,
action: #selector(handleButtonEvent(_:forEvent:)),
for: [.touchUpInside, .touchDown, .touchCancel, .primaryActionTriggered])
@objc func handleButtonEvent(_ sender: UIButton, forEvent event: UIEvent) {
// How do I tell which UIControl.Event triggered this?
}
From my understanding:
If I use the single-parameter version (@objc func handleButtonEvent(_ sender: UIButton)), I can’t distinguish which event fired.
If I use the two-parameter version with UIEvent, I can inspect touch.phase or event.type, but that feels indirect.
Questions:
Is there a recommended way to directly know which UIControl.Event caused the selector to fire?
Is sharing a single selector across multiple control events considered a good practice, or is it more common to register separate selectors per event?
Would appreciate guidance on what Apple recommends here.
I am building a centralized event handling system for UIKit controls and gesture recognizers. My current approach registers events using static methods inside a handler class, like this:
internal class TWOSInternalCommonEventKerneliOS {
internal static func RegisterTouchUpInside(_ pWidget: UIControl) -> Void {
pWidget.addTarget(
TWOSInternalCommonEventKerneliOS.self,
action: #selector(TWOSInternalCommonEventKerneliOS.WidgetTouchUpInsideListener(_:)),
for: .touchUpInside
)
}
@objc
internal static func WidgetTouchUpInsideListener(_ pWidget: UIView) -> Void {
print("WidgetTouchUpInside")
}
}
This works in my testing because the methods are marked @objc and static, but I couldn’t find Apple documentation explicitly confirming whether using ClassName.self (instead of an object instance) is officially supported.
Questions:
Is this approach (passing ClassName.self as the target) recommended or officially supported by UIKit?
If not, what is the safer alternative to achieve a similar pattern, where event registration can remain in static methods but still follow UIKit conventions?
Would using a shared singleton instance as the target (e.g., TWOSInternalCommonEventKerneliOS.shared) be the correct approach, or is there a better pattern?
Looking for official guidance to avoid undefined behavior in production.
In my SwiftUI iOS app, I need to detect which key (and modifier flags – Command, Option, Shift, Control) a user presses, but I don't want to pre-register them using .keyboardShortcut(_:modifiers:).
My use case is that keyboard shortcuts are user-configurable, so I need to capture the actual key + modifier combination dynamically at runtime and perform the appropriate action based on the user’s settings.
Questions:
What is the recommended way to detect arbitrary key + modifier combinations in SwiftUI on iOS?
Is there a SwiftUI-native solution for this, or should I rely on UIPressesEvent and wrap it with UIViewControllerRepresentable?
If UIKit bridging is necessary, what is the cleanest pattern for integrating this with SwiftUI views (e.g., Buttons)?
Any official guidance or best practices would be greatly appreciated!
I’m trying to understand the exact role of the return value in the UITextFieldDelegate method textFieldShouldReturn(_:).
From my experiments in Xcode, I observed:
Returning true vs false does not seem to cause any visible difference (e.g., the keyboard does not automatically dismiss either way).
I know that in shouldChangeCharactersIn returning true allows the system to insert the character, and returning false prevents it. That’s clear.
For textFieldShouldReturn, my current understanding is that returning true means “let the OS handle the Return press,” and returning false means “I’ll handle it myself.”
My confusion: what is it that the OS actually does when it “handles” the Return press?
Does UIKit do anything beyond calling this delegate method?
If the system is supposed to dismiss the keyboard when returning true, why doesn’t it happen automatically?
I’d appreciate clarification on the expected use of this return value — specifically, what default behavior the system performs (if any) when we return true.
Thanks!
I am observing an unexpected behavior with external keyboard input on iOS.
When I press Command + key (e.g., ⌘ + J) while a UITextView is focused, the system invokes
pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?)
twice:
-> Once with the key press event without any modifier flags.
-> A second time with the same key event but including the Command modifier flag.
This behavior is checked on an iPad with an external keyboard.
Additionally, I noticed that textView(_:shouldChangeTextIn:replacementText:) is not invoked in this case, even if I call super.pressesBegan for event propagation.
Questions:
Is it expected that pressesBegan fires twice for a Command + key combination?
If so, what is the recommended way to distinguish between these two invocations?
Should the UITextView delegate methods (like shouldChangeTextIn) be triggered for such key combinations, or is this by design?
Hi all,
I’m subclassing UITextView and overriding insertText(_:) to intercept and log input:
class TWTextView: UITextView {
override func insertText(_ text: String) {
print("insertText() : \(text)")
super.insertText(text)
}
}
This works fine, but I’ve noticed that insertText(_:) is invoked both when:
The user types something in the text view (via hardware/software keyboard).
I programmatically call myTextView.insertText("Hello") from my own code.
I’d like to be able to distinguish between these two cases — i.e., know whether the call was triggered by the user or by my own programmatic insert.
Is there any recommended way or system-provided signal to differentiate this?
Thanks in advance!
Hi all,
In my AppKit app, I sometimes simulate events programmatically, for example:
func simulateKeyPress(characters: String, keyCode: UInt16) {
guard let keyDown = NSEvent.keyEvent(
with: .keyDown,
location: .zero,
modifierFlags: [],
timestamp: 0,
windowNumber: NSApp.mainWindow?.windowNumber ?? 0,
context: nil,
characters: characters,
charactersIgnoringModifiers: characters,
isARepeat: false,
keyCode: keyCode
) else { return }
NSApp.postEvent(keyDown, atStart: false)
}
At the same time, I install a local event monitor:
NSEvent.addLocalMonitorForEvents(matching: .any) { event in
// Ideally, detect whether this event came from a real user
// (mouse, keyboard, trackpad, etc.)
// or was programmatically generated via NSEvent + postEvent.
return event
}
The problem:
Events I generate with NSEvent.* factory methods and post using NSApp.postEvent look the same as real system events when received in the monitor.
My question:
Is there a supported way to tell whether an incoming NSEvent is system/user-generated vs programmatically posted?
I've set up a Notification Content Extension for my app, but it's not getting called(tried both local and remote push). I've read the Apple dev guide, and I've set up everything as it says. https://developer.apple.com/documentation/usernotificationsui/customizing_the_appearance_of_notifications
I've looked over the common issues (setting proper deployment targets and setting category identifiers from the backend and in the .plist)
After receiving the notification, I'm not able to get the expanded view and neither is the didReceive(_ notification: UNNotification) of my extension view controller getting invoked. Is there something I'm missing while doing the extension setup, I m not able to figure out the problem?
Also, I m not able to understand this note from apple
"Notification content app extensions are supported only in iOS apps"
when all the Notification content Extension APIs are provided for MacOS also?
I have created a Notification service extension as target to the main MacOS application. I want to update the content of my remote notification using this extension but due to some reason the extension is not getting invoked to update my remote notification.
The auto execution of the below method seems to fail for my app extension.
didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping
(UNNotificationContent) -> Void)
I have tried the suggested solutions in this link but it did not help. Maybe there are some differences to using Notification service for MacOS and ios that I m not aware.
I am able to send normal remote notifications using the curl command, but it is not invoking the notification service extension. Below is the curl command.
curl -v --header "apns-topic: $TOPIC" --header "apns-push-type: alert" --header "authorization: bearer $AUTHENTICATION_TOKEN" --data '{"aps": {"mutable-content": 1,"alert": {"title": "Encrypted title","body": "Encrypted body"}},"MEETING_ORGANIZER": "MyMeet"}' --http2 https://${APNS_HOST_NAME}/3/device/${DEVICE_TOKEN}
Is there anything I m missing that is causing this problem?
I m using Mac Automator app to add new actions to the right click quick menu for files and folder. As can we seen in the image we have a number of actions available for mail app, Calendar, photos and other apps. I wanted to know whether something similar can be done for my app. I wanted to list my app in the library and provide some similar action options. Can it be done?
I have been using the Cpp-Swift Interoperability in Xcode15 for direct communication between Cpp and Swift code. It required a few Build settings changes for the Swift Compiler and creating clang modules to access cpp code in swift.
I wanted to use this interoperability feature in my visual studio project which is using Cmake. I m not able to find the Xcode attribute property flags for my cmake to enable this interoperability. Can someone help with this?
I am creating an Xcode project using xcode generator in Cmake. The project has a library which contains cpp files and swift files. I m trying to test swift-cpp interoperability that is introduced in xcode15 to perform direct cpp calls from swift and vice-versa. For this to work, we need to set a xcode build setting 'C++ and Objective-C Interoperability' which I m doing via cmake, Below is my cmake file:
cmake_minimum_required(VERSION 3.18)
project(CxxInterop LANGUAGES CXX Swift)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_Swift_LANGUAGE_VERSION 5.0)
add_executable(CxxInterop ./Sources/CxxInterop/main.swift
./Sources/CxxInterop/Student.cpp
)
#include the directory with modulemap file and Student.hpp
target_include_directories(CxxInterop PUBLIC
${CMAKE_SOURCE_DIR}/Sources/CxxInterop)
#setting the xcode C++ and Objective-C Interoperability setting
target_compile_options(CxxInterop PRIVATE
"-cxx-interoperability-mode=default")
when building the generated xcode project I get the error unknown argument: '-cxx-interoperability-mode=default'.
However the weird thing is when I separate out the cpp code in a different library and swift files in a different one, then this works and I m able to invoke the cpp methods in my swift file after importing the clang module from the module map file.
Is there any reason to why having cpp and swift files in same library producing this error? I m following this link to setup the project via cmake.
I am having a usecase where I wanted to detect the system language change event under OS X. I went throught the available options in NSNotification.Name , but did not find anything helpful. I found a similar link but it seems to be no longer applicable.
Any help on how this can be achieved?