I'm new to CoreStore and attempting to test my ability to create, store, and fetch CoreStore Objects correctly. It appears entries are being created based on results of dataStack.fetchCount() and transaction.create(), but the data is unavailable or not stored correctly based on my results of dataStack.fetchAll() (it says data: fault at the end of each object) and inspection of the SQLite database with Liya software reveals no entries in the table. I'm using CoreStore v8.0.1 and Xcode v12.4. My example code (using synchronous execution) is below. I appreciate your input into troubleshooting the issue. Thanks.
MyImage.swift:
import CoreStore
final class MyImage: CoreStoreObject {
#Field.Stored("desc")
var desc: String = ""
}
MyApp.swift
import SwiftUI
import CoreStore
import Foundation
#main
struct MyApp: App {
static let dataStack: DataStack = {
let dataStack = DataStack(
CoreStoreSchema(
modelVersion: "V1",
entities: [
Entity<MyImage>("MyImage")
],
versionLock: [
"MyImage": [..., ..., ..., ...]
]
)
)
try! dataStack.addStorageAndWait(
SQLiteStore( fileName: "MyStore.sqlite",
//localStorageOptions: .allowSynchronousLightweightMigration,
localStorageOptions: .recreateStoreOnModelMismatch
)
)
print(dataStack.coreStoreDumpString)
return dataStack
}()
init() {
CoreStoreDefaults.dataStack = MyApp.dataStack
try! dataStack.perform(
synchronous: { (transaction) in
let test_obj = transaction.create(Into<MyImage>())
test_obj.desc = "Description"
},
waitForAllObservers: true
)
do {
let objects = try dataStack.fetchAll(From<MyImage>())
print(objects)
} catch { print("error fetching")}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
I appreciate your help.
It turns out that the fetch results will display data:fault until the properties of the objects are accessed. The following example code will display the value of the properties:
let objects = try dataStack.fetchAll(From<MyImage>())
print(objects.map { $0.desc })
Related
I am struggling to extract single values (strings and Int) from the data I fetched from an API. I fetch the data in the form of a list:
class apiCall {
func getRockets(completion:#escaping ([Rockets]) -> ()) {
guard let url = URL(string: "https://api.spacexdata.com/v4/rockets") else { return }
URLSession.shared.dataTask(with: url) { (data, _, _) in
let rockets = try! JSONDecoder().decode([Rockets].self, from: data!)
print(rockets)
DispatchQueue.main.async {
completion(rockets)
}
}
.resume()
}
}
Then when I try using it in a View I succeed when using a List to view the values, like it shows the list of the names from the API data. But then when I want to view a single value like this:
import SwiftUI
struct RocketStatistics: View {
#State var rockets: [Rockets] = []
var body: some View {
VStack{
Text(rockets[1].name)
}
.onAppear {
apiCall().getRockets { (rockets) in
self.rockets = rockets
}
}
}
}
struct RocketStatistics_Previews: PreviewProvider {
static var previews: some View {
RocketStatistics()
}
}
It does not even give me an error, but my preview just won't update and keeps crashing.
So my question is how can I extract single values from this API data in List form and use these single values in my whole project?
To keep it simple and make it work first I started just with fetching the "name" from the API:
import Foundation
import SwiftUI
struct Rockets: Codable, Identifiable {
let id = UUID()
let name : String
}
When it all works I would also want to use Integer values from the API in my project, so tips on how to that are also welcome!
Never ever get items by a hard-coded index in a SwiftUI view without any check. When the view is rendered the first time the array is empty and any index subscription will crash.
Always check if the array contains the required number of items. In this case the array must contain at least two items
VStack{
Text(rockets.count > 1 ? rockets[1].name : "")
}
How can I pass data to a view and use it directly in the "header"? All tutorials I made are accessing the data in the view body - which works fine - but I want to call a graphlql method from the UpdateAccountView and than render a view based on the result.
My class for passing data:
class Account {
var tel: Int
init(tel: Int) {
self.tel = tel
}
}
My main view where the class is initialised (simplified - normally the "tel" will come from an input)
struct ContentView: View {
var account: Account = Account(tel: 123)
var body: some View {
NavigationView {
NavigationLink(
destination: UpdateAccountView(account: account),
label: {
Text("Navigate")
})
}
}
}
The view I call to do the request and call the next view based on the result
UpdateAccount is taking tel:Int as a parameter.
And here is the problem. I cannot access account.tel from the passed data.
struct UpdateAccountView: View {
var account: Account
#ObservedObject private var updateAccount: UpdateAccount = UpdateAccount(tel: account.tel)
#ViewBuilder
var body: some View {
if updateAccount.success {
AccountVerifyView()
} else {
ContentView()
}
}
}
The error:
Cannot use instance member 'account' within property initializer; property initializers run before 'self' is available
Update method (GraphQL):
class UpdateAccount: ObservableObject {
#Published var success: Bool
init(tel: Int){
self.success = false
update(tel: tel)
}
func update(tel: Int){
Network.shared.apollo.perform(mutation: UpdateAccountMutation(tel: tel)) { result in
switch result {
case .success(let graphQLResult):
self.success = graphQLResult.data!.updateAccount.success
case .failure(let error):
print("Failure! Error: \(error)")
self.success = false
}
}
}
I saw that there is an EnvironmentObject but than the variable become available globally as far as I understood, which is not necessary here.
Thank you for your help.
You can make it in explicit init, like
struct UpdateAccountView: View {
var account: Account
#ObservedObject private var updateAccount: UpdateAccount // << declare
init(account: Account) {
self.account = account
self.updateAccount = UpdateAccount(tel: account.tel) // << here !!
}
// ... other code
}
Good evening,
I'm implementing a Realm Database with SwiftUI.
The Database is made of a table containing "Projects" and a table containing "Measures" (relation one-to-many).
The main view displays the project list and "Measureview" displays the measures related to the project selected.
When I select a project, the measures list is displayed and then impossible to go back, the app crashes (simulator and real device).
Xcode points AppDelegate file : Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffedfd5cfd8)
I know that 4/5 months ago, some developers experienced this issue but I suppose that currently Apple fix the problem.
Please find below the relevant code :
Realm part :
import Foundation
import RealmSwift
import Combine
class Project : Object, Identifiable {
#objc dynamic var ProjectName = "" // primary key
#objc dynamic var ProjectCategorie = ""
#objc dynamic var ProjectCommentaire = ""
let Measures = List<Measure>() // one to many
override static func primaryKey() -> String? {
return "ProjectName"
}
}
class Measure : Object, Identifiable {
// #objc dynamic var id_Measure = UUID().uuidString // primary key
#objc dynamic var MeasureName = ""
#objc dynamic var MeasureDetail = ""
#objc dynamic var MeasureResult = ""
override static func primaryKey() -> String? {
return "MeasureName"
}
}
func createProject (_ title:String,_ categorie:String, _ commentaire:String) {
let realm = try! Realm()
let proj = Project()
proj.ProjectName = title
proj.ProjectCategorie = categorie
proj.ProjectCommentaire = commentaire
try! realm.write {
realm.add(proj)
}
}
//****************************************************************
class BindableResults<Element>: ObservableObject where Element: RealmSwift.RealmCollectionValue {
let didChange = PassthroughSubject<Void, Never>()
let results: Results<Element>
private var token: NotificationToken!
init(results: Results<Element>) {
self.results = results
lateInit()
}
func lateInit() {
token = results.observe { _ in
self.didChange.send(())
}
}
deinit {
token.invalidate()
}
}
Contentview :
struct ContentView : View {
#ObservedObject var Proj = BindableResults(results: try! Realm().objects(Project.self))
var body: some View {
NavigationView{
List(Proj.results) { item in
NavigationLink(destination: MeasureView(Pro: item) ){
ContenRowUI(Proj :item)
}
}
}
.navigationBarTitle(Text("Project List"))
}
}
Measure view :
struct MeasureView: View {
var Pro = Project() //= Project()
var body: some View {
NavigationView {
List(Pro.Measures) { item in
Text("Detail: \(item.MeasureDetail)")
}
.navigationBarTitle(Text("Measure"))
}
}
}
Additional information, if I replace Measureview by a simple textview, the behaviour is very weird :
I select a Project, the application shows the textview and goes back automatically to the main list (project list)
If someone could help me, I would be grateful.
Thanks a lot for your support.
Jeff
I am trying to make a Data-Storage using NSCoder, for some weird reason, its showing this error to me where i try to use the .encode keyword, please help me understand what i'm doing wrong..
let encoder = PropertyListEncoder()
do {
let data = try encoder.encode(self.itemArray) // <--- showing error here
} catch {
}
Never-mind, I found the problem! If you guys are facing the same problem where you make your array takes data specified in a class, you need to make the class 'Encodable' ie
import Foundation
class CellItemReg : Encodable { // <-- 'Encodable'
var done : Bool = false
var title : String = ""
}
This fixed for me in Swift iOS.
Inherit Codable in the class which you are trying to encode.
In your case,
let encoder = PropertyListEncoder()
do {
let data = try encoder.encode(self.itemArray) // <--- showing error here
} catch {
}
Let's assume itemArray is the array of a class named 'Item'. Then your 'Item' needs to inherit Codable in swift.
Just as below.
import Foundation
class Item: Codable {
var id: Int!
}
All the best!
Since I have updated to Xcode 7 and swift 2, I'm getting this errors:
No type named 'Query' in module 'SQLite'
Use of undeclared type 'Database'
using this code:
let table:SQLite.Query
init(db:Database){
table = db["BucketType"]
}
I'm using the swift2 branch of SQLite.swift, but it looks like my project, it can't find the reference SQLite.swift module.
Also have import SQLite on every file I use SQLite.swift with.
I've tried the manual integration and the cocoa pods, but with the same results.
It was working with Xcode 6.4.
I have something like this...
class DBHelper {
static let instance = DBHelper() // singleton
var db : Connection
init() {
do {
self.db = try Connection("\(Util.getDBPath())/db.sqlite3")
createTablesIfNotExists()
} catch {
Logger.error("Could not create a connection to database")
}
}
func createTablesIfNotExists() {
// Logs
let logs = Table(TLog.TABLE_NAME) // just the name of your table
do {
try db.run(logs.create(ifNotExists: true) { t in
t.column(TLog.ID, primaryKey: true) // Expression<Int>("id")
t.column(TLog.TS) // Expression<String>("ts")
t.column(TLog.TAG) // Expression<String>("tag")
t.column(TLog.TYPE) ...
t.column(TLog.CONTENT) ...
})
} catch {
Logger.error("Could not create table Logs")
}
}
And.. Util.getDBPath would be...
import SystemConfiguration
class Util {
class func getDBPath() -> String {
let path = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true
).first
return path!
}
}
Hope this help you.