Creating a unique ID for an object in YapDatabase - swift

Suppose I have a collection of Users in a YapDatabase. How do I assign each user a unique identifier upon creation?
struct User: Codable{
public var name: String
private var id: ???
}
I've seen UUID in the Apple developer documentation. Having done some reasearch, it seems more for use in distributed systems, athough I suppose it could work. Are there other alternatives? Is there a "standard" method for giving objects a unique id in a relational database?

Possible variants:
1) String (unique everywhere & forever)
struct User: Codable{
public var name: String
private var id: String // = UUID().uuidString
}
2) Int (unique inside your users context, enough in majority of cases)
struct User: Codable{
public var name: String
private var id: Int = 0 // = lastUser.id + 1, where 0 is a new non stored
}

Related

swift access modifiers correct usage

Suppose I have the following struct inside a StorageService framework :
struct Post {
public let author: String
public let description: String
public let image: String
public let likes: Int
public let views: Int
}
So to access its fields from another module I mark all fields with public keyword - it's clear. But should I mark the name Post itself to be public :
public struct Post ...
I tried both ways but I see no differences (with public struct Post and struct Post).
What is the right way to follow here?
The access modifier of the type itself will control the accessibility of the type and hence making any properties more accessible than the type itself is useless, since you cannot access properties of a type that you don't know about.
In order to be able to use the Post type from outside your framework, you need to declare Post as public.
This makes the type itself and all of its properties accessible from outside your framework:
public struct Post {
public let author: String
public let description: String
public let image: String
public let likes: Int
public let views: Int
}
On the other hand, if you don't want to expose some specific properties/methods publicly, you can always use an accessibility modifier that is stricter than the type's modifier.
public struct Post {
public let author: String
public let image: String
public let likes: Int
let description: String // can only be accessed from inside the module
private let views: Int // can only be accessed from the Post type itself
}

How to convert one struct to another with same variables Swift (iOS)?

I need help with converting one object to another. Might have searched 10-20 website didn't find any good answer.
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
I did this:
let say I have value UniversityGroupChatItem in variable universityGroupChatItem and my universityGroupChatItem contains is not nil and contains value. I tried this it did not work.
universityJoinChatViewModel = (universityGroupChatItem) as! UniversityJoinChatViewModel
The app crashed.
Then I tried:
map and
compactmap
None worked.
I am not getting how to convert UniversityGroupChatItem struct to UniversityJoinChatViewModel struct.
I do not understand how to convert one struct to another struct both has same number name variables.
You can't force cast one object into another (no matter struct, class, enum ect.) even if they are fully the same inside
You need to implement inits where one object takes fields from another one.
map is function to sequences, if You have only 1 object just init it with another one
Examples:
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
let universityGroupChatItem = UniversityGroupChatItem(id: 0, name: "name")
let universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)
let groupArray = Array(repeating: universityGroupChatItem, count: 10)
let joinArray = groupArray.map(UniversityJoinChatViewModel.init(nameOfModel:))
In your case, you already have the constructor that can help you to achieve what you want, so instead of trying to cast the object, create a new one:
universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)

RealmSwift: storing an element with a timestamp

I am trying to define a wrapper around objects I want to store in Realm. The wrapper should contain an additional date object so that I can filter old objects. So far I have this
public final class RealmDateTaggedRealmObject: ObjectFacade {
#objc public dynamic var date: Date?
#objc public dynamic var value: ObjectFacade?
#objc private dynamic var id: String = ""
public override class func primaryKey() -> String? {
return #keyPath(id)
}
public convenience init<T: RealmMappable>(from object: RealmDateTagged<T>) {
self.init()
date = object.date
value = object.value.asRealmObject
id = object.primaryKey
}
}
The RealmMappable protocol enables transforming implementing entities into ObjectFacade. The ObjectFacade class is an empty class that inherits from Object, because I got an exception if I declared
#objc public dynamic var value: Object?
So I tried to be smart and created ObjectFacade. Turns out I'm not so smart cause it always stores nil. Also, value can't be a generic type because it is not supported in Objective-C.
Any suggestions?
Thanks!

Best approach to make class design if we have two class as bellow :

Best approach to make class design if we have two class as below:
class Teacher {
var name
var age
var TechId
}
class Student {
var name
var age
var StdID
}
I try it using that :
class Person {
var name
var age
}
class Student : Person {
var StdID
}
class Teacher : Person {
var TechID
}
But now problem is that student become teacher and vice versa.
Can you any one provided best solutions for that using Swift?
You said:
But now problem is that student become teacher and vice versa.
If you can change back and forth like this, I'd first suggest a concrete and distinct object to capture what precisely is transitioning from one to the other:
class Person {
var name: String
var age: Int
}
Note, in your example, you are considering this Person to be what other languages consider to be an abstract/virtual class. But I'm suggesting that you want to make this a concrete object (the actual person) that you instantiate.
The question then becomes how you represent "student" and "teacher". One simple pattern is to consider it a question of membership in some relevant collection:
typealias StudentID = String
var students: [StudentID: Person]
typealias TeacherID = String
var teachers: [TeacherID: Person]
In that case, transitioning from a student to a teacher (or vice versa) is merely a question of adding/removing from the appropriate dictionaries.
The above is a bit constrained, though. For example, what if you wanted to keep track of more student-specific properties (e.g. enrollment date, etc.) or teacher-specific properties (e.g. hire date, social security number, annual salary, etc.). This suggests you might want specific types for these student and teacher types:
class Student {
let studentID: String
let person: Person
}
class Teacher {
let teacherID: String
let person: Person
}
And then your students and teachers collections become simple arrays:
var students: [Student]
var teachers: [Teacher]
But by making the Person a property (rather than a base class), if you know which person is associated with a particular "student id", you can now associate that person with a particular "teacher id", too. But the idea is the same, it's merely a question of membership in the appropriate collection/type, not an issue of trying to change the inherent type of the person.
The alternative is a protocol oriented pattern:
protocol Person {
var name: String { get }
var age: Int { get }
}
struct Student: Person {
let studentID: String
var name: String
var age: Int
init(name: String, age: Int) {
studentID = UUID().uuidString
self.name = name
self.age = age
}
init(person: Person) {
self.init(name: person.name, age: person.age)
}
}
struct Teacher: Person {
let teacherID: String
var name: String
var age: Int
init(name: String, age: Int) {
teacherID = UUID().uuidString
self.name = name
self.age = age
}
init(person: Person) {
self.init(name: person.name, age: person.age)
}
}
This captures your notion that Person is an abstract type that simply conforms to having certain properties. It avoids any ambiguity that Person is not a type, itself, but merely a protocol to which types have to conform. You can only instantiate concrete Student and Teacher objects.
But then, if you want to create a Teacher from a Student, you can do:
let fred = Student(name: "Fred", age: 22)
let teacher = Teacher(person: fred)
Note, though, that this doesn’t “change” fred into a Teacher, but rather creates a new Teacher whose Person properties are copies of those of fred.
For Swift, I would recommend something like this:
protocol Person {
var name: String { get }
var age: Int { get }
}
struct Teacher: Person {
let id: Int
let name: String
let age: Int
}
struct Student: Person {
let id: Int
let name: String
let age: Int
}
Use a Protocol to define the person. And use a Struct for Teacher and Student because once created you would not change their details as a Struct is immutable. Both Teacher and Student conform to Person protocol.
To test if a person is a Teacher or Student, you could do this:
func test(person: Person) {
switch person {
case is Teacher:
print("teacher")
case is Student:
print("student")
default:
preconditionFailure("Unknown person type")
}
}

Core Data One to Many Relationship not saving correctly/as expected

I have a core data project that includes the following NSManagedObjects:
********************** FSDJump NSManaged Object
extension FSDJump {
#nonobjc public class func fetchRequest() -> NSFetchRequest<FSDJump> {
return NSFetchRequest<FSDJump>(entityName: "FSDJump")
}
#NSManaged public var starSystem: String
#NSManaged public var starPos: NSArray
#NSManaged public var bodyName: String
#NSManaged public var jumpDist: Float
#NSManaged public var fuelUsed: Float
#NSManaged public var fuelLevel: Float
#NSManaged public var boostUsed: Bool
#NSManaged public var systemFaction: String
#NSManaged public var systemAllegiance: String
#NSManaged public var systemEconomy: String
#NSManaged public var systemGoverment: String
#NSManaged public var systemSecurity: String
#NSManaged public var powers: NSArray
#NSManaged public var powerplayState: String
#NSManaged public var timeStamp: String
#NSManaged public var factionState: String
#NSManaged public var factions: NSSet
}
// MARK: Generated accessors for factions
extension FSDJump {
#objc(addFactionsObject:)
#NSManaged public func addToFactions(_ value: Factions)
#objc(removeFactionsObject:)
#NSManaged public func removeFromFactions(_ value: Factions)
#objc(addFactions:)
#NSManaged public func addToFactions(_ values: NSSet)
#objc(removeFactions:)
#NSManaged public func removeFromFactions(_ values: NSSet)
}
********************** Factions NSManaged Object
extension Factions {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Factions> {
return NSFetchRequest<Factions>(entityName: "Factions")
}
#NSManaged public var name: String
#NSManaged public var allegiance: String
#NSManaged public var factionState: String
#NSManaged public var government: String
#NSManaged public var influence: Float
#NSManaged public var fsdJump: FSDJump
}
with a one to many relationship defined between FSDJump and Factions (i.e. one FSDJump may have multiple factions (with the inverse relationship defined as 'fsdJump').
I use the following code to save multiple Factions (where they exist) within an 'if else' statement saves each fsdJumpEvent.
if fsdJumpEvent["Factions"].exists() {
// save all of the Faction array objects in the variable arrayOfFactions
let arrayOfFactions = fsdJumpEvent["Factions"]
// create a newFaction managedObject to save the faction details to
let newFaction = (Factions(context: contextTCCEDJ))
for faction in arrayOfFactions {
// the following is strictly not necesary but it makes the code easier to read
// first allocate the values from faction to a local variable then allocate that variable to the newFaction managedObject
// Note faction is a tuple (string, JSON) so the construct 'faction.1' accesses the second value in the tuple
// 'faction.0' would access the first value in the tuple which is the array index "0", "1", "2", etc
let newFactionName = faction.1["Name"].string!
let newFactionState = faction.1["FactionState"].string!
let newFactionGovernment = faction.1["Government"].string!
let newFactionAllegiance = faction.1["Allegiance"].string!
let newFactionInfluence = faction.1["Influence"].float!
newFaction.name = newFactionName
newFaction.allegiance = newFactionAllegiance
newFaction.government = newFactionGovernment
newFaction.influence = newFactionInfluence
newFaction.factionState = newFactionState
// Add the new object to the context allowing it to be saved.
fsdJump.addToFactions(newFaction)
print("Faction added \(newFaction)")
}
}
The code appears to work. It builds, it runs and the print("Faction added \(newFaction)") statement prints multiple Factions per FSDJump as expected when they exist and as per the source data file I am using (JSON).
I can fetch the results and display them in a NSTableView. I can load data without any problems for the FSDJump managed object and display that in a NSTableView.
The fetch code is:
// Function returns all of the Factions associated with the timeStamp related entry in FSDJumps using the fsdJump relationship
func eventFactionsFetchSavedDataFromPersistenStore (contextTCCEDJ: NSManagedObjectContext, timeStamp: String) -> [Factions] {
var result = Array<Factions>()
let localFetchRequest = Factions.fetchRequest() as NSFetchRequest
localFetchRequest.predicate = NSPredicate(format:"fsdJump.timeStamp == '\(timeStamp)'")
do {
result = try contextTCCEDJ.fetch(localFetchRequest)
} catch {
print("Error in returning Factions event saved data from the persistent store")
}
print(result.count)
for reSult in result {
print(reSult.fsdJump.timeStamp)
}
return result
}
However, it only seems to save the last 'faction' for each relationship - rather than the multiple factions that are shown in the for faction in arrayOfFactions loop. Because the fetch statement only returns one Faction per fetch. Even if I remove the predicate statement it returns all of the saved factions but again only one has been saved per fsdJumpEvent instead of the multiple factions that are identified by the print statement.
I have tried everything I can think of. I have not been able to find a previous question that relates to this specific issue.
Am I using the 'addToFactions' function incorrectly?
Any help would be gratefully received.
(And yes - for any Elite Dangerous fans out there I am writing a macOS app to parse my journal files as a companion app to my windows version of Elite Dangerous.)
You are creating a new, single instance of newFaction outside of your for faction in arrayOfFactions loop. So that single newFaction is used each time the loop runs and just assigns new values to it (overwriting previous values) resulting in it ending up with the last set of values. Hence you seeing a single faction with the 'last' set of values. Move the line:
Let newFaction = Factions(context: contectTCCEDJ)
Inside (at the beginning) of the for in loop.
Edit: you are adding your faction to a Set (which by definition requires unique entities) so all you're currently doing is re-adding the same faction each time rather than a new one. To-many relationships point to a Set.