Post not yet marked as solved
I have a multiplatform app where I support iOS, macOS and tvOS. There is one target which supports it all. In my assets catalog I have the AppIcon entry which holds the app icon for iOS and macOS. This works as expected. However the tvOS app icon is ignored. I added an "tvOS App Icon & Top Shelf Image" asset to my asset catalog and filled it with my icons for tvOS.
Then I added it in the target’s general settings App Icon entry under App Icons and Launch Screen like shown in the screenshot.
What am I missing? What needs to be done to make this work?
Post not yet marked as solved
I have an app which uses SwiftUI and Mac Catalyst. When running on a Mac I want to provide a preferences menu entry with the usual keyboard shortcut Command + ,. An implementation via the Settings bundle is out of question since my preferences are too complex for this.
Here is a reduced example of my implementation:
import SwiftUI
@main
struct PreferencesMenuTestApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: UIResponder, UIApplicationDelegate {
override func buildMenu(with builder: UIMenuBuilder) {
let preferencesCommand = UIKeyCommand(title: "Preferences…",
action: #selector(showPreferences),
input: ",",
modifierFlags: .command)
// let preferencesCommand = UIAction(title: "Preferences…") { action in
// debugPrint("show preferences")
// }
let menu = UIMenu(title: "Preferences…",
options: .displayInline,
children: [preferencesCommand])
builder.insertSibling(menu, afterMenu: .about)
}
@objc
func showPreferences() {
debugPrint("show preferences")
}
}
The problem is that the menu entry is disabled. Obviously the provided selector is not recognised. When I mark the AppDelegate with @main, then the menu entry is enabled. Of course then the app's window is empty.
When I switch to the UIAction implementation (the out commented code) it works fine. But since one cannot provide a keyboard shortcut for UIActions this is not a good solution.
What am I missing? How would one implement a preferences menu entry that actually works?
Post not yet marked as solved
I want to recreate an user experience like in the settings app in tvOS. Therefore I have a HStack with some content on the left side and a List of NavigationLinks on the right side.
However a focused link in the list gets clipped on the left side. I tried paddings and spacers and what not, but nothing helped. Is this is a bug or am I missing something?
Here is some example code to show the problem:
struct ContentView: View {
var body: some View {
NavigationStack {
HStack(spacing: 20) {
VStack(alignment: .center) {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
List {
ForEach(SomeViewEnum.allCases) { someView in
NavigationLink(someView.rawValue, value: someView)
}
}
.navigationDestination(for: SomeViewEnum.self) { someView in
Text(someView.rawValue)
}
}
}
}
}
And a screenshot to show the problem:
Post not yet marked as solved
I am building a tvOS app which divides the screen into two parts horizontally. Both sides have buttons. I want a certain button on the right side to have focus. To achieve that I am marking the enclosing HStack with .focusScope() and then use .prefersDefaultFocus(in:) on the button which should have focus.
This works fine, even if I add another focus scope inside (see source code). But as soon as I wrap the HStack in a NavigationView it falls apart. The scope is not set as intended, instead the left view always gets the focus.
Am I missing something? Is this intended? I’m a little lost right now.
I am targeting tvOS 16.4 and using Xcode 14.3.1.
Fun fact: The simulator view inside Xcode displays the view correctly. The simulator and an actual device are not.
Here is an example to showcase that:
struct ContentView: View {
@Namespace private var mainNamespace
@Namespace private var rightNamespace
var body: some View {
// NavigationView {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
HStack {
VStack {
Button("left") {}
}
VStack {
Button("right 1") {}
Button("right 2") {}
.prefersDefaultFocus(in: rightNamespace)
}
.focusScope(rightNamespace)
.prefersDefaultFocus(in: mainNamespace)
}
.focusScope(mainNamespace)
.padding(.top, 50)
}
.padding()
// }
}
}
I am using Xcode 15 and working on a localised app. I use the new String Catalogs feature which works great for my app. In my app I created some local package like Apple has done it in the Backyard Birds example. However the translations I did in the package's String Catalog won’t be used in the app. What am I doing wrong?
For my app I use a struct for my CoreData persistence controller like so:
struct PersistenceController {
static var shared = PersistenceController()
// more code omitted for brevity
}
As a development asset I made an extension to the PersistenceController to provide a special instance for previews with some sample data.
extension PersistenceController {
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
// create some sample data
return result
}()
}
Now I want to use the special preview instance with the new #Preview macro in Xcode beta 2. The deployment target for the app is set to iOS 17.
#Preview {
var context = PersistenceController.preview.container.viewContext
return SpanList()
.preferredColorScheme(.light)
.environment(\.managedObjectContext, context)
}
But the preview fails to build due to the following error:
Type 'PersistenceController' has no member 'preview'.
My experiments show that everything I add to the PersistenceController via an extension is not available in the preview macro. This is no matter where I place the extension. Even when it’s placed in the same file as the PersistenceController itself.
Am I missing something or is this intended behaviour?
Post not yet marked as solved
I’ve got this simple view and it doesn’t work as expected. When clicking the button a new Eventis created and the flag used as binding for a sheet is set to true. This should show the sheet and give the sheet access to the Event. Instead I get the error message Fatal error: Unexpectedly found nil while unwrapping an Optional value.
I can’t see the problem. As far as I see this the tmpEvent variable should have a valid value once the sheet is presented.
import SwiftUI
struct TestView: View {
@Environment(\.managedObjectContext) private var viewContext
@State private var showingSheet = false
@State private var tmpEvent: Event?
var body: some View {
VStack {
Button(action: showSheet) {
Label("Add event", systemImage: "plus.circle")
}
}
.sheet(isPresented: $showingSheet) {
Text("event title: \(tmpEvent!.descriptionString)"). // Fatal error occurs here
}
}
private func showSheet() {
tmpEvent = Event(context: viewContext)
showingSheet = true
}
}
Any ideas why this isn’t working?
Post not yet marked as solved
In my app I’ve got a list view and a view for displaying the rows in the list. When I delete an item from that list the app crashes in the row view stating an illegal access.
I don’t understand why the row view is rendered again for the deleted item.
The list view:
import Foundation
import SwiftUI
struct SpanList: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [ NSSortDescriptor(keyPath: \Span.startDate,
ascending: true) ],
predicate: NSPredicate(format: "isArchived != YES"),
animation: .default)
private var activeSpans: FetchedResults<Span>
var body: some View {
NavigationView {
VStack {
List {
Section(header: ActiveSectionHeader()) {
ForEach(activeSpans, id: \.id) { item in
NavigationLink(destination: getConfiguredEditView(span: item)) {
SpanRow(span: item)
}
.buttonStyle(PlainButtonStyle())
.listRowBackground(item.color.opacity(0.5))
}
.onDelete(perform: deleteItems)
}
}
.listStyle(GroupedListStyle())
}
}
}
private func getConfiguredEditView(span: Span) -> some View {
EditSpan(span: span)
.navigationTitle("Edit Span")
.navigationBarTitleDisplayMode(.inline)
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
// Necessary due to a bug in the framework. Without this the app crashes
// with a bug stating multiple access from different threads is not
// allowed.
viewContext.perform {
offsets.map {
activeSpans[$0]
}.forEach(viewContext.delete)
PersistenceController.shared.save()
}
}
}
}
The row view:
import SwiftUI
import CoreData
struct SpanRow: View {
@ObservedObject var span: Span
var body: some View {
HStack(alignment: .center) {
VStack(alignment: .leading) {
HStack {
if span.showOnStartPage && !span.isArchived {
Image(systemName: "paperclip")
}
Text(span.descriptionString)
.font(.headline)
.fontWeight(.bold)
}
Spacer()
HStack {
// It crashes here
Text("\(span.startDate, formatter: dateFormatter)")
Text("–")
if span.usesEndDate {
Text("\(span.endDate, formatter: dateFormatter)")
} else {
Image(systemName: "infinity")
}
}
}
Spacer()
if let daysSinceStart = span.daysSinceStart {
VStack {
Text("\(daysSinceStart)")
.font(.largeTitle)
.fontWeight(.semibold)
Text("days")
}
}
}
.padding(.vertical, 5)
}
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
}
What am I missing?