'Font' is not convertible to 'Font?' Swift UI - xcode

apparently I'm having this error that says 'Font is not convertible to 'Font?' in the code. Any suggestions ? Thanks! Here is the code below. I'm not sure exactly what's causing the issue. Everything seems to be fine before this.
import SwiftUI
struct ContentView: View {
#Environment(\.managedObjectContext) var managedObjectContext
#FetchRequest(fetchRequest: ToDoItem.getAllToDoItems()) var toDoItems:FetchedResults<ToDoItem>
#State private var newTodoItem = ""
var body: some View {
NavigationView {
List{
Section(header: Text("What's next ?")) {
HStack{
TextField("New Item", text: self.$newTodoItem)
Button(action: {
let toDoItem = ToDoItem(context: self.managedObjectContext)
toDoItem.Title = self.newTodoItem
toDoItem.createdAt = Date()
do {
try self.managedObjectContext.save()
} catch {
print(error)
}
self.newTodoItem = ""
}){
Image(systemName: "plus.circle.fill")
.foregroundColor(.green)
.imageScale(.large)
}
}
}.font(.headline)
Section(header: Text("To Do's")) {
ForEach(self.toDoItems) {todoItem in
ToDoItemView(title: todoItem.title!, createdAt: "\(todoItem.createdAt!)")
}
}
}
.navigationBarTitle(Text("My List"))
.navigationBarItems(trailing: EditButton())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

To make it compilable you need explicitly specify type here
}.font(Font.headline)
and here
.foregroundColor(Color.green)

The problem is inside the Button action:
toDoItem.Title = self.newTodoItem
Change Title to title.
In general, when you get weird error messages in SwiftUI, just try to comment out lines until the error goes away. This will help you find the problematic code.

Related

Sending an NSManagedObjectID to a struct / view

I'm complete new to swift, swiftui and coredata. I have good programming experience in other languages, but swift is its own world. :-)
Important information: it's for macOS not iOS!!
My problem: I want to edit a Dataset in an separate view displayed in a sheet. I followed this example (SwiftUI update view on core data object change), but when trying to run, my NSManagedObjectID is allway nil.
The ContentView (shortened)
import SwiftUI
import CoreData
struct ContentView: View {
#State public var selectedBookId: NSManagedObjectID?
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Books.title, ascending: true)],
animation: .default)
private var books: FetchedResults<Books>
#State private var showingEditScreen = false
var body: some View {
NavigationView {
List {
ForEach(books, id: \.self) { book in
HStack {
NavigationLink {
HStack {
Button {
// here store objectID to var
selectedBookId = book.objectID
showingEditScreen.toggle()
} label: {
Label("", systemImage: "pencil")
}
}
.padding(10.0)
} label: {
Text(book.title!)
}
}
}.onDelete(perform: deleteBooks)
}
.toolbar {
ToolbarItem(placement: .automatic) {
// here goes blabla
}
}
Text("Bitte zuerst ein Buch auswählen!")
}
.sheet(isPresented: $showingEditScreen) {
// Run EditBookView an send bookId
EditBookView(bookId: selectedBookId).environment(\.managedObjectContext, self.viewContext)
}
}
}
My EditView looks like this
import SwiftUI
struct EditBookView: View {
#Environment(\.managedObjectContext) var moc
#Environment(\.dismiss) var dismiss
var bookId: NSManagedObjectID! // This is allways nil!!
var book: Books {
moc.object(with: bookId) as! Books
}
#State private var title = ""
#State private var review = ""
var body: some View {
Form {
Text("Edit Book").font(.title)
Spacer()
Section {
TextField("Buchname", text: $title)
TextEditor(text: $review)
} header: {
Text("Schreibe eine Zusammenfassung")
}
Spacer()
Section {
HStack {
Button("Save") {
// add the book
// here code for update
try? moc.save()
dismiss()
}
Button("Cancel") {
print(bookId) // shows "nil"
dismiss()
}
}
}
Spacer()
}
.onAppear {
self.title = self.book.title ?? ""
self.review = self.book.review ?? ""
}
.padding(10.0)
}
}
First: thanks for all the good hints. In the end, I could solve the problem using
#ObservedObject var aBook: Books
at the beginning of my EditView.
The button itself has the following code
Button {
showingEditScreen.toggle()
} label: {
Label("", systemImage: "pencil")
}.sheet(isPresented: $showingEditScreen) {
EditBookView(aBook: book).environment(\.managedObjectContext, self.viewContext)
}
This way, I can send the whole book object of a single book item to the edit view and I can use it.

Line limit in TextEditor (SwiftUI) not working

I've seen a lot of answers that simply say to use the limit limit view modifier but it doesn't seem to work:
mport SwiftUI
struct TextEditorTest: View {
#State var text: String = "Type in here"
var body: some View {
VStack {
Text("Sample Text A")
TextEditor(text: $text)
.lineLimit(3)
Spacer()
}
}
}
struct TextEditorTest_Previews: PreviewProvider {
static var previews: some View {
TextEditorTest()
}
}

Unmodified SwiftUI / Core Data default app code does not run in simulator?

When I create and run a new, unmodified, Core Data / SwiftUI app project in Xcode (12.3), the simulator shows a blank screen. Code below.
Upon creation of the new app project, SwiftUI code is generated that includes a List along with Add and Edit buttons. The UI displays correctly in Xcode's preview but not in the simulator.
This is the default code in the ContentView.swift file:
import SwiftUI
import CoreData
struct ContentView: View {
#Environment(\.managedObjectContext) private var viewContext
#FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
List {
ForEach(items) { item in
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
}
.onDelete(perform: deleteItems)
}
.toolbar {
#if os(iOS)
EditButton()
#endif
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
do {
try viewContext.save()
} catch {
// Replace this...
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
// Replace this...
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}
private let itemFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .medium
return formatter
}()
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
You can reproduce this simply by creating a new iOS App project with SwiftUI and Core Data enabled:
Trying to wrap my head around this stuff. Getting stuck on the default code is not promising!
IMHO Yes this seems like a bug with the example, might be worth submitting with a feedback
Problem:
Since the view is not inside the navigation view the navigation buttons are not visible
The tool bar modifier requires to use the ToolbarItem which is missing.
Overview:
Please wrap the view contents inside a NavigationView
Wrap the tool bar buttons inside ToolbarItem
Solution:
Replace the body computed property as follows:
var body: some View {
NavigationView {
List {
ForEach(items) { item in
Text("Item at \(item.timestamp!, formatter: itemFormatter)")
}
.onDelete(perform: deleteItems)
}
.toolbar {
#if os(iOS)
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
#endif
ToolbarItem(placement: .navigationBarLeading) {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
}

Send data to next view - SwiftUI

So I have been trying to get a simple pass of data working with SwiftUI.
Basically the below script prints out a list of items (in a HStack) I then have each one linked to our Podcast() view.
What I am trying to do is pass through the podcast name to the next view. How do I achieve
this? As all the examples are about int which I am not using am using a String.
import SwiftUI
import RemoteImage
struct ContentView: View {
#State private var showAlert = false
#State var posts: [Program] = []
var body: some View {
NavigationView {
if posts.isEmpty {
Text("Loading")
} else {
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .bottom, spacing: 10) {
ForEach(posts) { post in
//return
NavigationLink(destination: Podcasts()){
RemoteImage(type: .url(URL(string:post.icon)!), errorView: { error in
Text(error.localizedDescription)
}, imageView: { image in
image
.resizable()
.renderingMode(.original)
/* .clipShape(Circle())
.shadow(radius: 10)
.overlay(Circle().stroke(Color.red, lineWidth: 5))*/
.aspectRatio(contentMode: .fit)
.frame(width:200, height:200)
}, loadingView: {
Text("Loading ...")
})
}
}
}.frame(height: 200)
}.frame(height: 200)
}
}.onAppear {
Api().getPosts { (posts) in
self.posts = posts
}
}.navigationBarTitle(Text("Home"))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The podcast View
import SwiftUI
struct Podcasts: View {
var body: some View {
NavigationView{
Text("Hello")
}.navigationBarTitle(Text("Podcast"))
}
}
struct Podcasts_Previews: PreviewProvider {
static var previews: some View {
Podcasts()
}
}
Pass post as constructor argument, like
ForEach(posts) { post in
//return
NavigationLink(destination: Podcasts(post: post)){
so now
struct Podcasts: View {
let post: Program
var body: some View {
// !! DON'T ADD SECOND NAVIGATION VIEW IN STACK
// !! - THERE MUST BE ONLY ONE
Text(post.name)
.navigationBarTitle(Text("Podcast"))
}
}

Why cant I see my for Each loop in the preview view in XCode

I am making a to do list to learn about Core data. I noticed when I add a ForEach loop to read my core data entries, it stops loading the view and the app crashes. If I replace the ForEach loop with a Text("Hi"), it all works. However the app runs perfectly in simulator.
import SwiftUI
struct ContentView: View {
#Environment(\.managedObjectContext) var managedObjectContext
#FetchRequest(fetchRequest: ToDoItem.getAllToDo()) var toDoItems:FetchedResults<ToDoItem>
#State private var newTodoItem = ""
#State private var selection = 0
var body: some View {
NavigationView {
List {
Section (header: Text("Whats... next")) {
HStack{
TextField("New Item", text: self.$newTodoItem)
Button(action: {
let toDoItem = ToDoItem(context: self.managedObjectContext)
toDoItem.title = self.newTodoItem
toDoItem.createdAt = Date()
do {
try self.managedObjectContext.save()
}catch {
print(error)
}
self.newTodoItem = ""
}){
Image(systemName: "plus.circle.fill")
.foregroundColor(.green)
.imageScale(.large)
}
}
}.font(.headline)
Section(header: Text("To Do's")){
ForEach(self.toDoItems) {todoItem in
HStack{
VStack(alignment: .leading){
Text(todoItem.title!)
.font(.headline)
Text("\(todoItem.createdAt!)")
.font(.caption)
}
}
}.onDelete {indexSet in
let deleteItem = self.toDoItems[indexSet.first!]
self.managedObjectContext.delete(deleteItem)
do {
try self.managedObjectContext.save()
}catch {
print(error)
}
}
}
}
.navigationBarTitle(Text("My List"))
.navigationBarItems(trailing: EditButton())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Any idea what the issue is?

Resources