FWIW It's a quite simple app slightly modified from the Xcode template for CoreData + CloudKit project.
struct FeedbackContentView: View {
@Environment(\.managedObjectContext) private var context
@FetchRequest private var items: FetchedResults<Item>
var body: some View {
NavigationStack {
List {
ForEach(items) { item in
let creator = CoreDataStack.shared.container.record(for: item.objectID)?.creatorUserRecordID?.recordName
VStack(alignment: .leading) {
Text(item.timestamp!.formatted())
Text("Mine")
.foregroundStyle(.secondary)
.opacity(creator == "__defaultOwner__" ? 1 : 0)
Text("Can Edit? \(CoreDataStack.shared.container.canUpdateRecord(forManagedObjectWith: item.objectID))") // Always `true`
}
}
}
}
}
}
Post
Replies
Boosts
Views
Activity
View is actually a protocol that ContentView is implementing and not inheriting. You can read about in the Swift Book:
https://docs.swift.org/swift-book/LanguageGuide/Protocols.html
Regarding the some word, it's something called Opaque Type and it's a way to hide the actually type of whatever you return from the body. Also worth reading in the book:
https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html
You can use @UIApplicationDelegateAdaptor to provide an AppDelegate:
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
return true
}
}
@main
struct SampleApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
I have the same problem and it really bothers me.
Grids are just a way to organize Views, very much like Stack, without all the special powers of List inherited from UITableView. You have to manually handle the selection and here's a simple approach:
struct ContentView: View {
@State var selectedItem = 0
var body: some View {
ScrollView {
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 3)) {
ForEach((0...100), id: \.self) { item in
Rectangle()
.fill(item == selectedItem ? Color.blue : Color.gray)
.aspectRatio(1.0, contentMode: .fit)
.onTapGesture {
selectedItem = item
}
}
}
}
}
}
This is actually a little complex to do. You should definitely watch the great talk "SwiftUI under the hood" given by Chris Eidhof in BA: Swiftable conferece. He goes through the entire process of creating a dynamic circular button while explaining some interesting details of the framework. The video is available on Youtube.
Under the hood there is a UIKit TableView for a SwiftUI List, so it makes sense given that UITableViewCells are reused.
It's works using the App protocol. I believe UIApplication it's not going anywhere in the near future at least until there is a SwiftUI way to do all the things that are still not possible without UIKit.
Here is an example that uses CoreLocation to provide a MKCoordinateRegion to a Map:
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var region = MKCoordinateRegion()
private let manager = CLLocationManager()
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locations.last.map {
let center = CLLocationCoordinate2D(latitude: $0.coordinate.latitude, longitude: $0.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
region = MKCoordinateRegion(center: center, span: span)
}
}
}
struct ContentView: View {
@StateObject private var manager = LocationManager()
var body: some View {
Map(coordinateRegion: $manager.region, showsUserLocation: true)
}
}
You can use the datePickerStyle modifier to set the style for a DatePicker as following:
struct ContentView: View {
@State private var birthdate = Date()
var body: some View {
DatePicker("Date of Birth", selection: $birthdate, displayedComponents: .date)
.datePickerStyle(WheelDatePickerStyle())
}
}
DefaultDatePickerStyle (iOS, macOS)
The default DatePicker style.
WheelDatePickerStyle (iOS)
A system style of date picker that displays each component as columns in a scrollable wheel.
FieldDatePickerStyle (macOS)
A system style that displays the components in an editable field.
GraphicalDatePickerStyle (iOS)
A system style of DatePicker that displays an interactive calendar or clock.
StepperFieldDatePickerStyle (macOS)
A system style that displays the components in an editable field, with adjoining stepper that can increment/decrement the selected component.
Use the Feedback Assistant to report this and other bugs:
https://feedbackassistant.apple.com
You can manage the App life cycle using @Environment(\.scenePhase) and @UIApplicationDelegateAdaptor as following:
class AppDelegate: NSObject, UIApplicationDelegate {
func applicationDidFinishLaunching(_ application: UIApplication) {
print(#function)
}
}
@main
struct SampleApp: App {
@Environment(\.scenePhase) private var scenePhase
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { phase in
switch phase {
case .active:
print("active")
case .inactive:
print("inactive")
case .background:
print("background")
}
}
}
}
Unfortunately I believe the only alternative without using a UIColorPickerViewController is to convert the description (which returns a hexadecimal value) property of the Color from HEX to RGBa.
Yes, you can setup everything you need directly in your App as following:
@main
struct SampleApp: App {
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
MovieList()
.environment(\.managedObjectContext, persistentContainer.viewContext)
}
.onChange(of: scenePhase) { phase in
switch phase {
case .active:
print("active")
case .inactive:
print("inactive")
case .background:
print("background")
saveContext()
}
}
}
var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "SampleApp")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
func saveContext() {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
You can send a UIResponder.resignFirstResponder action to UIApplication.shared:
struct ContentView: View {
@State private var text = ""
var body: some View {
VStack {
TextField("Enter something here", text: $text).fixedSize()
Button("Done") {
let resign = #selector(UIResponder.resignFirstResponder)
UIApplication.shared.sendAction(resign, to: nil, from: nil, for: nil)
}
}
}
}