I have an NSStatusBar application. This is my first in SwiftUI. And I need to know when the window is closed so that I can disable some of menu commands. I can use NSWindowDelegate with AppDelegate as follows.
import SwiftUI
@main
struct SomeApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject private var menuViewModel = MenuViewModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(menuViewModel)
}
}
}
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
private var menuViewModel = MenuViewModel()
func applicationDidFinishLaunching(_ notification: Notification) {
if let window = NSApplication.shared.windows.first {
window.setIsVisible(false)
window.delegate = self
}
}
func windowWillClose(_ notification: Notification) {
menuViewModel.windowClosed = true
}
}
When the window will close, MenuViewModel (ObservableObject) will receive a call, which I want my ContentView to receive. But, so far, it won't.
import SwiftUI
struct ContentView: View {
var body: some View {
ZStack {
...
...
}
.onReceive(statusBarViewModel.$windowClosed) { result in
// never called...
}
}
}
Can a SwiftUI View receive a call somehow when its window closes? Muchos thankos.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have a simple document-based application for macOS.
struct ContentView: View {
@Binding var document: TextDocument
var body: some View {
.onReceive(NotificationCenter.default.publisher(for: .notificationTextWillAppendSomeTextt), perform: { _ in
})
VStack {
TextEditor(text: $document.text)
}
}
}
extension Notification.Name {
static let notificationTextWillAppendSomeTextt = Notification.Name("TextWillAppendSomeText")
}
Suppose that my application currently has three tabs. If I call a menu command through
post(name:object:)
this menu command call will affect all three of them. This stackoverflow topic talks about it, too. So how could I tell which window should get a call and others don't? Thanks.
I've been waiting since I had Organizer sent my latest IPA to iTunes Connect servers 40 minutes ago. But the App Store Connect site doesn't show it. Is anyone having the same issue? I hate it when it happens because you don't know how long you have to wait.
Topic:
App Store Distribution & Marketing
SubTopic:
App Store Connect
I have three toolbar buttons with images from Assets.xcassets. Initially, I didn't use @1x, @2x, @3x sizes. I just put one size (72 x 72) for all of them. It was never a problem till a few days ago.
The reviewer has reported numerous issues, which all seem to originate from miniaturized toolbar images. They have given me a screenshot from an iPad. Now, each of the three to the left has shrunken to 4 x 4, according to them.
Some lines of code are the following.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationStack {
ZStack {
VStack {
...
...
...
}
.background(.brown)
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems(
leading: HStack(content: {
Button {
} label: {
Image("ToolbarImage1")
.resizable()
.foregroundColor(.red)
.aspectRatio(contentMode: .fit)
.frame(width: 28)
}
Button {
} label: {
Image("ToolbarImage2")
.resizable()
.foregroundColor(.cyan)
.aspectRatio(contentMode: .fit)
.frame(width: 28)
}
Button {
} label: {
Image("ToolbarImage3")
.resizable()
.foregroundColor(.gray)
.aspectRatio(contentMode: .fit)
.frame(width: 28)
}
}),
trailing: HStack(content: {
Button {
} label: {
Text("X")
.font(.body)
.fontWeight(.semibold)
.foregroundStyle(colorScheme == .light ? .white : .black)
.frame(width: 28, height: 28)
.background {
Circle()
.fill(!disableGroupMenu ? .green : .green.opacity(0.6))
}
}
Button {
withAnimation(.easeInOut(duration: 0.2)) {
showCopyMenu.toggle()
manageMenu()
}
} label: {
Text("Y")
.font(.body)
.fontWeight(.semibold)
.foregroundStyle(colorScheme == .light ? .white : .black)
.frame(width: 28, height: 28)
.background {
Circle()
.fill(!disableCopyMenu ? .indigo: .indigo.opacity(0.6))
}
}
})
)
.toolbar {
ToolbarItem(placement: .principal) {
Text("App name")
.bold()
.foregroundColor(.white)
}
}
}
}
}
}
I don't see this minituralization issue on any of my actual devices (iPhone XR, iPhone 14, iPad 9th gen.) on top of various simulator models including iPad A16 with iOS 26. This is my first iOS submission after iOS 26 was released. I don't know if it has something to do with iOS 26. The reviewer hasn't told me about their iPad model or the iOS version. I have the same app for macOS, which was submitted after macOS 26 was released. And they haven't reported the miniaturization issue after 4 or 5 software updates.
If you have any idea as to what's causing it, please let me know. I have submitted a new binary with @3x as a resort. I doubt the issue has been resolved. Thanks.
Initally, I've used Xcode 16.4 to built the app. I have tried building it with Xcode 26. And I don't see the minituralization issue on any of the simulator models (iPad mini, iPad A16...).
Topic:
UI Frameworks
SubTopic:
SwiftUI
I'm trying to understand how Combine works. The following is my sample code.
import UIKit
import Combine
class ViewController: UIViewController {
// MARK: - Variables
var cancellable: AnyCancellable?
// MARK: - IBAction
@IBAction func buttonTapped(_ sender: UIButton) {
currentValueSubject.send(20)
}
// MARK: - Life cycle
var currentValueSubject = CurrentValueSubject<Int, Never>(1)
override func viewDidLoad() {
super.viewDidLoad()
let cancellable = currentValueSubject
.sink { value in
print("New value: \(value)")
}
currentValueSubject.send(5)
currentValueSubject.send(10)
//currentValueSubject.send(completion: .finished)
currentValueSubject.send(15)
//cancellable.cancel()
}
}
If I run it with the iPhone simulator, I get
New value: 1
New value: 5
New value: 10
New value: 15
If I tap the button, the app won't get a new value. I suppose that's because the subscription is cancelled at the end of viewDidLoad? If so, why does it get cancelled? I don't quite see a practical side of Combine's Subject. When is it useful? Thanks.
I'm playing with Picker and have come up with some unexpected results. As shown below, I have three pickers in a form.
struct PickColorView: View {
@State var numberIndex: Int = 4
@State var textSizeIndex: Int = 0
var body: some View {
NavigationView {
Form {
Picker(selection: $numberIndex, label: Text("Numbers")) {
ForEach((0...20), id: \.self) {
Text("\($0)")
}
}.onChange(of: numberIndex) { newIndex in
print("Index: \(newIndex)")
}
Picker(selection: $textSizeIndex, label: Text("textSizeTitle")) {
ForEach([14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60], id: \.self) { textSize in
Text("\(textSize)")
}
}.onChange(of: textSizeIndex) { newIndex in
print("Index: \(newIndex)")
}
}
.navigationBarTitle("Settings")
.navigationBarHidden(false)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
Well, if I run it, the top picker shows its initial selection (4) while the other doesn't. I wonder why? The following is a screenshot. (Please ignore the top picker appearing in the screenshot).
If I go ahead and select one with the bottom picker, I end up with an actual value instead of the index. So if I select 18 (Please see the screenshot below.), I expect to get 2 with the onChange thing. But I get 18, instead. So how can I receive the index?
Muchos thankos.
When I write code with UIKIt or Cocoa, I usually create and use FileManager.default in AppDelegate or a base view controller. In Cocoa, for example, I would write something like the following.
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
let defaultFileManager = FileManager.default
func applicationDidFinishLaunching(_ aNotification: Notification) {
}
func applicationWillTerminate(_ aNotification: Notification) {
NSApp.terminate(nil)
}
}
import Cocoa
class HomeViewController: NSViewController {
let appDelegate = (NSApp.delegate as! AppDelegate)
override func viewDidLoad() {
super.viewDidLoad()
if appDelegate.defaultFileManager.fileExists(atPath: some file path) {
}
}
}
So my question is where I can create FileManager.default so that I use it under different Views in SwiftUI? Muchos thankos.
I have a simple project as follows.
import SwiftUI
class GameSettings: ObservableObject {
@Published var score: Int = 100
}
struct ContentView: View {
@StateObject var settings = GameSettings()
var body: some View {
GeometryReader { geo in
ZStack {
HStack(spacing: 0.0) {
RightView().environmentObject(GameSettings())
.frame(width: geo.size.width / 2.0, height: geo.size.height)
Spacer()
}
VStack {
HStack {
Spacer()
Button {
print("\(settings.score)")
} label: {
Text("Print")
.font(.largeTitle)
}.padding(.trailing, 40.0)
}
Spacer()
}
}
}
}
}
struct RightView: View {
@EnvironmentObject var settings: GameSettings
var body: some View {
ZStack {
Color.red
Button {
settings.score += 100
} label: {
Text("Change")
.font(.largeTitle)
}
}.environmentObject(settings)
}
}
So the score is supposed to increase by 100 if I tap the button over the red area. And I want to print the latest value by tapping the Print button at the top-right corner. But it will remain at 100. What am I doing wrong? And can I achieve my goal without using an @ObservedObject variable? Thanks.
I have a @State variable with an array of strings with which to create instances of TextField. So far, I have the following lines of code.
import SwiftUI
struct ContentView: View {
@State private var names: [String] = ["Jim Thorton", "Susan Murphy", "Tom O'Donnell", "Nancy Smith"]
var body: some View {
HStack {
ForEach($names, id: \.self) { $name in
TextField("", text: $name)
.fixedSize()
.padding(.horizontal, 20.0)
.background(Color.orange.opacity(0.2))
}
}
}
}
I wonder if there is a simple way of aligning instances of TextField horizontally such that one that exceeds the screen width will go to the next line like the following picture?
Thanks.
I have downloaded a sample project at raywenderlich.com (https://www.raywenderlich.com/22408716-drag-and-drop-editable-lists-tutorial-for-swiftui). I am working on a project involving DropDelegate. And I have a question with this project to make my point.
In reference to the picture shown below, if I grab, drag and move Count Sheep, its preview picture will shrink. How could I prevent the preview picture from shrinking its size?
struct ContentView: View {
@EnvironmentObject private var todoList: TodoList
@State private var isShowingAddTodoView = false
@State private var editMode: EditMode = .inactive
@State private var focusId: Int?
func addTodo() {
isShowingAddTodoView = true
}
var body: some View {
NavigationView {
VStack {
FocusTodoView(focusId: focusId)
.padding()
.onDrop(
of: [TodoItem.typeIdentifier],
delegate: TodoDropDelegate(focusId: $focusId))
ScrollView {
ActiveTodoView()
CompletedTodoView()
.disabled(editMode.isEditing)
.onDrop(of: [TodoItem.typeIdentifier], isTargeted: nil) { itemProviders in
for itemProvider in itemProviders {
itemProvider.loadObject(ofClass: TodoItem.self) { todoItem, _ in
guard let todoItem = todoItem as? TodoItem else { return }
DispatchQueue.main.async {
todoList.updateTodo(withId: todoItem.id, isCompleted: true)
}
}
}
return true
}
}
.applyPlainListAppearance()
.navigationBarTitle("Drag Todo")
.toolbar {
ToolbarItemGroup(placement: .navigationBarTrailing) {
EditButton()
Button(action: addTodo) {
Image(systemName: "plus")
}
.disabled(editMode.isEditing)
}
}
.environment(\.editMode, $editMode)
.sheet(isPresented: $isShowingAddTodoView) {
AddTodoView()
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
I wish I had a simpler sample. That's the only sample I have been able to find. Anyway, I've been asking Google all day about "SwiftUI DropDelegate preview" with no luck. Thanks.
I have an array of dictionaries. And I need to sort this array in an ascending order.
someArray = someArray.sorted { lValue, rValue in lValue.categoryName < rValue.categoryName }
So one of the dictionaries is categoryName. Now, I have a case where the category name of an array element is something specific, say 'price,' then that element must be listed at the end as an exception to the rule above. Is that possible? Thanks.
I have downloaded the UniversalMac_13.0_22A379_Restore.ipsw file. How do we use this file to install the new OS? Thanks.
How do you save a picture from the capture-screen with AVCaptureSession to Photo? My capture-screen looks like a square as show below.
Yet I've ended up with an 1080 × 1920 image as shown below. I have an iPhone XR, and I always end up with 1080 × 1920 images. How come the aspect ration never changes?
My code has the following lines
import UIKit
import AVFoundation
class CaptureViewController: UIViewController, AVCapturePhotoCaptureDelegate {
var captureSession: AVCaptureSession!
var cameraDevices: AVCaptureDevice!
var imagePhotoOutput: AVCapturePhotoOutput!
enum CameraCase {
case front
case back
}
// MARK: - IBAction
@IBAction func takePictureTapped(_ sender: UIButton) {
snapPicture()
}
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
prepareCamera(cameraCase: .back)
}
// MARK: - Camera
func prepareCamera(cameraCase: CameraCase) {
/* removing existing layers */
if let sublayers = self.view.layer.sublayers {
for sublayer in sublayers {
if sublayer.isKind(of: AVCaptureVideoPreviewLayer.self) {
sublayer.removeFromSuperlayer()
}
}
}
/* creating a capture session */
captureSession = AVCaptureSession()
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: cameraCase == .front ? .front : .back).devices.first else { return }
let videoInput = try? AVCaptureDeviceInput(device: device)
if captureSession.canAddInput(videoInput!) {
captureSession.addInput(videoInput!)
imagePhotoOutput = AVCapturePhotoOutput() // setting output destination
captureSession.addOutput(imagePhotoOutput) // adding photo output to session
}
/* creating a capture layer */
let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init(session: captureSession)
previewLayer.frame = CGRect(x: 0.0, y: 200.0, width: view.frame.width, height: view.frame.height - 500.0)
previewLayer.videoGravity = AVLayerVideoGravity.resize
/* adding video capture layer to the view layer */
self.view.layer.addSublayer(previewLayer)
/* starting capture session */
DispatchQueue.global(qos: .background).async {
self.captureSession.startRunning()
}
}
func snapPicture() {
let settingsForMonitoring = AVCapturePhotoSettings()
imagePhotoOutput?.capturePhoto(with: settingsForMonitoring, delegate: self as AVCapturePhotoCaptureDelegate)
}
// MARK: - Delegate methods
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error == nil {
guard let imageData = photo.fileDataRepresentation() else {
print("Error while generating image from photo capture data.");
return
}
if let image = UIImage(data: imageData) {
saveImage(image)
}
}
}
// MARK: - Saving an image to Photo Library
func saveImage(_ image: UIImage) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError: contextInfo:)), nil)
}
@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
print("An error has occurred: \(error.localizedDescription)")
} else {
print("Saved...")
}
}
}
Thanks.
Drawing a pie isn't difficult if I do it with Path.
import SwiftUI
struct ContentView8: View {
var body: some View {
PieSlice(start: .degrees(-90), end: .degrees(120))
.fill(.pink)
}
}
struct PieSlice: Shape {
let start: Angle
let end: Angle
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
path.move(to: center)
path.addArc(center: center, radius: rect.midX, startAngle: start, endAngle: end, clockwise: false)
return path
}
}
Actually, I want to animate this pie such that it will gradually deploy starting at -90 degrees. In the code above, I suppose I cannot animate the pie because the PieSlice guy isn't a View. Or can I? If I can't, is there an alternative way of drawing a pie so that I can animate it?
Thanks a million.
Señor Tomato Source
Hostage Negotiator at
Tomato Source Association of North America
I have followed a tutorial written by Hacking with Swift ( https://www.hackingwithswift.com/books/ios-swiftui/how-to-combine-core-data-and-swiftui) about Core Data in SwiftUI. The Entity name is Student. And it has two properties: name (String), id (UUID). And the following is my code.
import SwiftUI
struct CoreView: View {
@Environment(\.managedObjectContext) var managedObject
@FetchRequest(sortDescriptors: []) var students: FetchedResults<Student>
var body: some View {
VStack {
List(students) { student in
Text(student.name ?? "Unknown")
}
Button {
let firstNames = ["Gary", "Harry", "Elane", "Ray", "Nancy", "Jim", "Susan"]
let lastNames = ["Johns", "McNamara", "Potter", "Thompson", "Hampton"]
if let selectedFirstName = firstNames.randomElement(), let selectedLastName = lastNames.randomElement() {
let newStudent = Student(context: managedObject)
newStudent.id = UUID()
newStudent.name = "\(selectedFirstName) \(selectedLastName)"
try? managedObject.save()
}
} label: {
Text("Add")
}
}
}
}
struct CoreView_Previews: PreviewProvider {
static var previews: some View {
CoreView()
.environmentObject(DataController())
}
}
If I list all records and then add a new student to the list, the app will insert the last addition at a random row. I wonder if I can order these records by the creation date?
Muchos thankos