Basically I am trying to implement a class for a Person and Person's pets. In it's very simple form Person class and Pet class would be like this:
class Person {
var email : String!
var name : String!
var pets : [Pet]!
init(userName: String) {
email = userName
// load Person from CloudKit database
}
}
class Pet {
var name : String!
var breed : String?
}
Now I want to be able to load all Pets related to the specific userName. If I have the above the class, that only holds one Pet. If I do an array like in the Person class, there is no Load method. The question is, should I create a new class Pets like below:
class Pets {
var userName : String
var pets : [Pet]
init(email: String) {
// load all pets related to user here
}
}
Does this make sense? Or is there a better way to structure the class? Is my question clear enough? Thanks for any help in advance.
I'd be using structs not classes for my data model. Structs and Classes
I wouldn't use optionals unless I really had to, and there are a few use cases where you have to. I also wouldn't be using implicitly unwrapped optionals at all... i.e. ! It's an 'exclamation' for a reason. You should read up on when to use the different types of optionals.Why create implicitly unwrapped optionals
I wouldn't have a Pets class like you created. All this would be stored in your database to be queried ... possibly core data, or if you had some other class to hold the data it would be simply a dictionary/map of [String: [Pet]] and you could look up all the pets for a username from that dictionary/map
Related
I have a structure name Feature, i hope it can be generic.
struct Feature<T> {}
I have another two type: Person, Dog.
struct Person {}
struct Dog {}
What i want to ask is:
Can i call different functions or different property in Feature according to differrent T
//for Person type
let feature = Feature<Person>()
feature.hair// i want this visible for Person
feature.fur// i want this invisible for Person
//for Dog type
let feature = Feature<Dog>()
feature.hair// i want this invisible for Dog
feature.fur// i want this visible for Dog
I don't know the full scope of your situation so I am only answering your question. See below:
protocol GenericFeatureProtocol {
var eyeColor : String? { get set }
//other shared properties & functions
}
struct Person : GenericFeatureProtocol {
var eyeColor: String?
var hair: String?
}
struct Dog : GenericFeatureProtocol {
var eyeColor: String?
var fur: String?
}
As you can see, the GenericFeatureProtocol defines the shared properties and functions that are to be implemented by those comforting to it. The properties respective to Person stay on Person, and those respective to Dog stay on Dog.
I have a subclass of Object in Realm called BrowserCategory, and Artist, Decade and Genre are subclasses of BrowserCategory.
Right now each subclass of BrowserCategory has this LinkingObject property songs:
let songs = LinkingObjects(fromType: Song.self, property: "decade")
(for the Decade subclass, for example)
I'd like to write this in the BrowserCategory base class so I've tried this:
var songs = LinkingObjects(fromType: Song.self, property: className().lowercased())
However this returns the base class name and not the subclass name, giving the following error:
- Property 'Song.browsercategory' declared as origin of linking objects property 'Decade.songs' does not exist
Is there a way to do this the way I want to?
You are probably looking for type(of:self), which is polymorphic, as this demonstration illustrates:
class BrowserCategory {
func className() -> String {
return String(describing:type(of:self))
}
}
class Artist : BrowserCategory {}
class Decade : BrowserCategory {}
class Genre : BrowserCategory {}
let a = Artist()
a.className() // "Artist"
I should caution you, however, that to ask for a class's name as a string is a very odd thing to do. It is more usual to work with a class type as a type.
Consider this typical example, sometimes seen in tutorials, etc (even in Apple's code):
protocol Nameable {
var name: String {get}
}
struct Person : Nameable {
var name: String
}
My question is, what would be the benefit of this pattern? I can understand it once a function is added to a protocol, but what could be a good application for a protocol with just one or more variables? Why not just add name to each struct and class ?
Persons are not the only not the only things that you may want to name. Pets have names, roads have names, heck, some people name their cars.
What if we want to name each object in a collection of different objects? If we store those objects in a collection of Any, we don't have any way to guarentee that all objects have names.
This is where protocols come in. By creating a Nameable protocol, we can create a collection of Nameable objects, and be certain that all the objects within are guaranteed to have a name.
Here's an example:
protocol Nameable {
var name: String {get}
}
struct Person : Nameable {
let name: String
let age: Int
// other properties of a Person
}
struct Pet : Nameable {
let name: String
let species: String
// other properties of a Pet
}
struct Car : Nameable {
let name: String
let horsepower: Double
// other properties of a Car
}
let namableItems: [Nameable] = [
Person(name: "Steve", age: 21),
Pet(name: "Mittens", species: "Cat"),
Car(name: "My Pride and Joy", horsepower: 9000)
]
for nameableItem in namableItems {
print("\(nameableItem.name) is a \(nameableItem.dynamicType).")
}
Which prints:
Steve is a Person.
Mittens is a Pet.
My Pride and Joy is a Car.
You can try it here.
Basically you make a promise that your class / struct will contain defined properties.
For structures this is very important because they can't be subclassed.
Also, subclass can only have 1 superclass so you can't create Person who has more than one parent.
I would recommend you to read this article about why use protocols over subclassing and the main purpose of using them:
http://alisoftware.github.io/swift/protocol/2015/11/08/mixins-over-inheritance/
The key to the answer lies in the word protocol.
Protocol is a system of rules that explain the correct conduct and
procedures to be followed in formal situations.
That said, when you state that an object (struct, enum, class, ..) must conform to a protocol, you are obliged to respect it. If you do not, Xcode throws an error.
So one of the main, (absolutely not the only utility) is that you can not forget to include the attributes and / or functions in the various objects.
This could be very useful if multiple developers are working on the same code, or simply to avoid potential human error of distraction :) .
Another great advantage of the protocols is that they can be used as types.
Therefore a struct, enum, or different classes, which inherit the same protocol, they can all be traced to the same type.
Realm demo database has sample objects with inverse connection: objectReference has a link to RealmTestClass1.
class RealmTestClass1: Object {
dynamic var integerValue = 0
let arrayReference = List<RealmTestClass0>()
}
class RealmTestClass2: Object {
dynamic var boolValue = false
dynamic var objectReference: RealmTestClass1?
}
How to re-create that same structure? What code is needed for objectReference property to create that same link to parent object property?
Links in Realm are unidirectional. So if a to-many property Person.dogs links to a Dog instance and a to-one property Dog.owner links to Person, these links are independent from one another. Appending a Dog to a Person instance’s dogs property, doesn’t automatically set the dog’s owner property to this Person. Because manually synchronizing pairs of relationships is error prone, complex and duplicates information, Realm exposes an API to retrieve backlinks described below.
With inverse relationships, you can obtain all objects linking to a given object through a specific property. For example, calling Object.linkingObjects(_:forProperty:) on a Dog instance will return all objects of the specified class linking to the calling instance with the specified property. It’s possible to simplify this pattern by defining a read-only (computed) owners property on Dog:
class Person: Object {
// ... other property declarations
let dogs = List<Dog>()
}
class Dog: Object {
dynamic var name = ""
dynamic var age = 0
var owners: [Person] {
// Realm doesn't persist this property because it only has a getter defined
// Define "owners" as the inverse relationship to Person.dogs
return linkingObjects(Person.self, forProperty: "dogs")
}
}
This was taken from Realm's docs on relationships, which I encourage you to read.
I am searching how to get not managed property names and types of a NSManagedObject subclass.
here is few sample code to help me to ask my question :
#objc(Operation)
public class Operation : NSManagedObject {
#NSManaged var name: String
#NSManaged var amount: NSNumber
}
#objc(Account)
public class Account: NSManagedObject {
#NSManaged var bic: String
#NSManaged var number: String
#NSManaged var operations: Set<Operation>
#NSManaged var servicesSubscriptions: Set<ServiceSubcription>
// and more.
}
extension Account
{
public var lastOperation : Operation {
get
{
return self.operations.last
}
set(value)
{
self.operations.insert(value)
}
}
}
I have found many ways to get property names using reflect() function. reflect() do not work with NSManagedObject at all. (like this simple one)
edit
I have found examples with class_copyPropertyList function, that retrieve correctly property names, but don't found yet how to get types. Thank to Tom Harrington comment. (see that sample)
I have found many ways to get Attributes (or relations) of managed objects using NSEntityDescription. (like this one). Which work and get back bic and number, but not lastOperation.
edited
updated code sample to match better to reality
So my question is :
How to get back my lastOperation property, and its type, dynamically at run time ?
edit, what i am trying to do
I am parsing json, dnamically using reflection.
I need the type (or type name) of a property knowing only its name (i have "lastOperation", and need to get back Operation, or "Operation"). Once i get the type i can instanciate an object, then populate its own properties, using same mechanism (recursively).
Thank you for any help
When you get the list of properties using class_copyPropertyList, you can iterate through the list to look at each property in turn:
var propertyCount : UInt32 = 0
let properties = class_copyPropertyList(Account.self, &propertyCount)
for var i=0; i<Int(propertyCount); i++ {
let property = properties[i]
let propertyName = String(UTF8String: property_getName(property))
....
}
The type of each property is contained in one of the property attributes, as a string:
let propertyType = property_copyAttributeValue(property, "T")
let propertyTypeString = String(UTF8String: propertyType)
For your lastOperation property the string will look something like #\"Operation\". You'll have to clean up that string a little to get Operation.
I wrote a blog post a while ago describing something similar to what you're trying to do. The code is in Objective-C but all the functions, methods, etc are the same.
There is no way that I know of when it comes to a NSManagedObject. However, I would suggest creating title as a transient property inside of your model and then it will show up as part of the entity description.