Storing an array of custom objects in Realm - swift

I have an object called List which subclasses Realm's Object class:
class List: Object {
dynamic var brandListItems: [BrandListItem] = []
}
and another object, BrandListItem which also subclasses to Object:
class BrandListItem: Object {
dynamic var brandID: String?
dynamic var name: String?
}
My app is crashing with the following error
'Property 'brandListItems' is declared as 'NSArray', which is not a supported RLMObject property type. All properties must be primitives, NSString, NSDate, NSData, NSNumber, RLMArray, RLMLinkingObjects, or subclasses of RLMObject.
I tried doing something like RLMArray<BrandListItem>() with no luck. How do I successfully save these objects to Realm?

You need to use Realm's List<T> property. Note that it's not marked dynamic
https://realm.io/docs/swift/latest/#to-many-relationships
class List: Object {
let brandListItems = RealmSwift.List<BrandListItem>()
}
Note that it's necessary to qualify Realm Swift's List<T> with its module to disambiguate it from your newly-declared List class.

Related

How to pass a class object to a function but prevent mutation?

I can't see where in the Swift language is the facility to pass a class object to a function yet prevent that function from mutating the object by either calling functions that will implicitly mutate it or setting public variables. I'm gathering that this facility just does not exist, can anyone confirm?
That is to say, all objects are always mutable everywhere they can be seen.
This is extremely common throughout Cocoa. You create an immutable class and a mutable subclass. For examples, see AVComposition/AVMutableComposition, CBService/CBMutableService, CNContact/CNMutableContact.
In ObjC, this is common practice with collections as well (arrays, dictionaries, etc), but since those are value types in Swift, there's no need to use the classes (NSArray/NSMutableArray).
In Swift, rather than creating two classes, you create an immutable protocol and a class:
protocol Person: AnyObject {
var name: String { get }
var address: String { get }
}
class MutablePerson: Person {
var name: String = ""
var address: String = ""
}
Now, any function that accept Person will have an immutable object, and any function that accepts MutablePerson will be able to mutate it. This is a general pattern you can use to give different parts of your program access to different slices of the object's API. It's much more general and flexible than just const.
That said, this is not as common a pattern in Swift as it is in ObjC, since in most cases where this is useful, the type should be a struct anyway. But it is absolutely available if needed.
To your question about doing this with two classes, as in ObjC, it's possible, as long as you define both in the same file. It's just a bit tedious:
public class Person {
public fileprivate(set) var name: String = ""
public fileprivate(set) var address: String = ""
}
public class MutablePerson: Person {
public override var name: String {
get { super.name }
set { super.name = newValue }
}
public override var address: String {
get { super.address }
set { super.address = newValue }
}
}
It's possible a property wrapper could improve this, but I haven't been able to figure out how.
There's no way I can think of to allow usage of methods, but properties are no problem**. Just use an Immutable as a function parameter.
final class Class {
var property = true
}
var object = Immutable(Class())
object.property = false // Cannot assign to property: 'object' is immutable
/// An affordance for accessing the properties of an object
/// without the ability to mutate them.
#dynamicMemberLookup
public struct Immutable<Object: AnyObject> {
private let object: Object
}
// MARK: - public
public extension Immutable {
init(_ object: Object) {
self.object = object
}
subscript<Value>(dynamicMember keyPath: KeyPath<Object, Value>) -> Value {
object[keyPath: keyPath]
}
}
** The getters could be mutating, and they could return mutating closures. đŸ˜œ But that's an issue with the protocol approach as well. The best that we can do right now is a generally accurate hack.
What you are looking for are value types (such as structs). If you mutate any properties of a value type, you mutate the instance itself.
This means that when you pass a value type to a function, the function won't be able to mutate any of the properties of said value type.
On the other hand, classes are reference types, so mutating any of their properties doesn't mutate the class instance itself. Because of this, you cannot ban functions from modifying mutable properties of the class (unless you make them setter of said properties private).

Detect if a Realm object comforms to a specific protocol

I made a protocol called Synchronizable and I have some of my Realm objects conformed to this protocol.
Such as :
class Comment : Object, Synchronizable {
// ...
}
I want to query all of local Realm objects, and retrieve all objects that are conformed to this protocol.
So I did something like :
func getObjectsToSynchronize() -> [Object]{
Array(realm.objects(Object.self)).filter({
if let $0 = $0 as? Synchronizable {
return true
}
return false
})
}
With Object the Realm Object type, but this type object by default doesn't implements my protocol, so I can't detect if the object is conform to the protocol Synchronizable, it says :
Expression pattern of type 'Object' cannot match values of type 'Synchronizable?'
Is there a way to do this ? I think I'm on the wrong way by querying in the Realm object.
Wrong way?
Maybe I have to create another Realm class object called SynchronizableObjectthat inherits from Object realm class.
This class will have a relationship to Realm objects that I want to be Synchronizable, such as :
class SynchronizableObject : Object {
// MARK: - Realm Relationships
dynamic var synchronizables : List<Object>()
}
And then I should query this class with the Realm object
#AnthonyR you can't query/filter directly RealmSwift.Object, you must inherit your model from RealmSwift.Object as you'v done
class Comment : Object, Synchronizable {
// ...
}
Then you can query/filter all objects of inherited type:
func getObjectsToSynchronize() -> Results<Comment> {
return realm.objects(Comment.self)
}
If you explain a little more what do you want to do may be I can help you

setting property of nsobject subclass by means of selector setProperty

I have subclass of NSObject and I can set value of my subclass with:
performSelector(onMainThread: Selector("setNameOfProperty:"), with: "myName", waitUntilDone: true)
Actually, I did not write any method named setMethodProperty of course.
So here is my simple class:
class Post: NSObject {
var name: String?
var statusText: String?
var profileImageName: String?
var statusImageName: String?
var numLikes: NSNumber?
var numComments: NSNumber?
var location: Location?
override func setValue(_ value: Any?, forKey key: String) {
if key == "location" {
location = Location()
location?.setValuesForKeys(value as! [String: AnyObject])
} else {
super.setValue(value, forKey: key)
}
}
}
A then from another class I just invoke method performSelector:
let samplePost = Post()
samplePost.performSelector(onMainThread: Selector("setStatusText:"), with: "myName", waitUntilDone: true)
I am looking for any information about that interesting thing, but I couldn't. Maybe someone has the link about it or just know what is this behavior. If you can write about it to clarify situation.
Read more about key-value coding in About Key-Value Coding, specifically:
Objects typically adopt key-value coding when they inherit from NSObject (directly or indirectly), which both adopts the NSKeyValueCoding protocol and provides a default implementation for the essential methods. Such an object enables other objects, through a compact messaging interface, to do the following:
Access object properties.
The protocol specifies methods, such as the generic getter valueForKey: and the generic setter setValue:forKey:, for accessing object properties by their name, or key, parameterized as a string. The default implementation of these and related methods use the key to locate and interact with the underlying data, as described in Accessing Object Properties.
By subclassing NSObject, Post class implements NSKeyValueCoding.
Basically it means that the properties defined in Post generate corresponding getter and setter methods, which means that they can be accessed using performSelector. This Key-Value coding allows you to perform selectors for getting or setting even properties which names you don't know during compilation - selector can be created from a string variable.
In case you will decide to migrate the project to Swift 4, note that you will have to either mark each property that you want to access this way using #objc, or use #objcMembers annotation on the whole class.

Swift: Storing a Dictionary/Array of a Custom Object in a Core Data Managed Object Property

I am trying to implement the following 'Session' object in Core Data. All properties except the exerciseLog can be saved and accessed properly in Core Data. The way I currently have this set up allows me to manipulate the 'Session' object instance when it is in memory once it has been created, but upon saving the ManagedContext, the Object does not save exerciseLog property persistently and it is stored as nil instead.
This likely happens because when the object is in memory the transient value of the exerciseLog property can be manipulated, but the persistent storage of it is not implemented. I do not know how to properly implement the ability to allow the exerciseLog dictionary; with String key, and value as a custom object, 'Set' array, to be stored when the managed context is saved. The Set object is not a managed object by Core Data. It is just a regular object that the Session Object should reference and store (i.e not involved in the object graph with relationships). Note: I imagine if there is a solution for this, then it would also work if the 'Set' class was a struct, which would have been my preference.
import Foundation
import CoreData
#objc(Session)
class Session: NSManagedObject {
#NSManaged var exerciseLog: [String: [Set]]
#NSManaged var sessionDate: NSDate
#NSManaged var sessionDuration: NSNumber
#NSManaged var routineForSession: Routine
}
class Set: NSObject, Printable{
var reps: Int!
var weight: Double!
}

What's the difference between class methods and instance methods in Swift?

protocol NoteProtocol {
var body: NSString? { get set }
var createdAt: NSDate? { get set }
var entityId: NSString? { get set }
var modifiedAt: NSDate? { get set }
var title: NSString? { get set }
// class methods
class func insertNewNoteInManagedObjectContext(managedObjectContext: NSManagedObjectContext!) -> NoteProtocol
class func noteFromNoteEntity(noteEntity: NSManagedObject) -> NoteProtocol
// instance methods
func update(#title: String, body: String)
func deleteInManagedObjectContext(managedObjectContext: NSManagedObjectContext!)
}
Hi
This is a piece of code I found on GitHub. In this protocol, what is the main difference between class methods and instance methods? How they are defined?
Can anyone help me?
Some text from the documentation:
Instance Methods
Instance methods are functions that belong to instances of a particular class, structure, or enumeration. They support the functionality of those instances, either by providing ways to access and modify instance properties, or by providing functionality related to the instance’s purpose.
ie. An Instance of the class has to call this method. Example :
var a:classAdoptingNoteProtocol=classAdoptingNoteProtocol()
a.update()
Class Methods
Instance methods, as described above, are methods that are called on an instance of a particular type. You can also define methods that are called on the type itself. These kinds of methods are called type methods. You indicate type methods for classes by writing the keyword class before the method’s func keyword, and type methods for structures and enumerations by writing the keyword static before the method’s func keyword.
They are what are called as Static methods in other languages.To use them, this is what I would do:
var b=classAdoptingNoteProtocol.noteFromNoteEntity(...)
This will return a instance of a class which adopts NoteProtocol. ie. you don't have to create a instance of the class to use them.
Below the definition of instance methods and class methods (called type methods in Swift).
For more details you can browse the method section of the Swift documentation
Instance methods:
Instance methods are functions that belong to instances of a particular class, structure, or enumeration. They support the functionality of those instances, either by providing ways to access and modify instance properties, or by providing functionality related to the instance’s purpose. Instance methods have exactly the same syntax as functions
Type methods:
Instance methods, as described above, are methods that are called on
an instance of a particular type. You can also define methods that are
called on the type itself. These kinds of methods are called type
methods. You indicate type methods for classes by writing the keyword
class before the method’s func keyword, and type methods for
structures and enumerations by writing the keyword static before the
method’s func keyword.
Basically you can call type method (class method) without instance:
var myNoteProtocol = NoteProtocolAdoptImplClass.noteFromNoteEntity(...);
While you need to instantiate for instance methods:
var myNoteProtocol = NoteProtocolAdoptImplClass()
myNoteProtocol.update(...)