Instance of Realm Object subclass is null when init - ios

I'm new to iOS development and swift, and I'm using Realm for my swift project.
First, I create a subclass of Realm Object:
enum EnumA: Int {
case ValueA
case ValueB
}
class ClassA: Object {
var propA: EnumA = EnumA.ValueA
var propB: Double = 0.0
}
Then I have another class:
class ClassB: Object {
var id = 0
var name: String = ""
let aLotOfA = List<ClassA>()
override static func primaryKey() -> String? {
return "id"
}
}
Then I create instance of ClassB somewhere:
class ClassC: NSObject {
static let cManager = ClassC()
func defaultB() -> ClassB {
let instanceA = ClassA()
let instanceB = ClassB()
instanceB.name = "String"
instanceB.aLotOfA.append(instanceA)
return instanceB
}
}
And I have this class:
class ClassD: Object {
let aB: ClassB = ClassC.cManager.defaultB()
}
When I call defaultB(), the first line (let instanceA = ClassA()) makes instanceA null. I keep receiving message in the console like this:
"Object type '(null)' does not match RLMArray type 'ClassA'."
or
"The `ClassD.aB` property must be marked as being optional."
I don't know what's wrong here. Please someone help me, thanks very much.
And my environment:
Mac OS X 10.11.1 + Xcode 7.1
Realm is latest (Just downloaded from realm.io)
Base SDK: iOS 9.1
Deployment Target: iOS 9

As pointed out by zuziaka, you will need to declare all your persisted properties with dynamic var. This doesn't apply for List and RealmOptional properties.
Furthermore Realm doesn't support enums. You will need to declare your property ClassA.propA as Int and use the rawValue to initialize its default value:
class ClassA {
var propA: Int = EnumA.ValueA.rawValue
…
}
To-one relationships must be always marked as optional. That's here the case for the property ClassD.aB.

Related

Why do my linking objects not have a Realm?

In my iOS app, I get the following exception:
'Linking objects notifications are only supported on managed objects.'
when I try to add an observer block:
y.xxx.observe { ... }
to a property that is defined as such:
class Y: Object {
...
let xxx = LinkingObjects(fromType: X.self, property: "y")
...
}
I believe this means that y.xxx does not have a Realm, and indeed I can see in the debugger that y.xxx.realm is nil. However, y.realm is NOT nil.
How can the linking objects not have a Realm if the object I am linking to does have one?
For completeness, this is how Class X is defined:
class X: Object {
...
#Persisted var y: Y?
...
}
Realm version 10.11.0, RealmDatabase version 11.1.1.
Context: I am in the last phase of migrating an app that was originally written in ObjC to be purely in Swift. This means switching to the Swift version of Realm. I have not encountered this problem in the previous version of the app that is largely the same code base except that it uses a very old version of the Realm framework and the Realm objects are defined in ObjC.
You can add an observer to a linking objects property as long as the objects are managed. Let me set this up starting with the PersonClass who has a List property of DogClass objects
class PersonClass: Object {
#objc dynamic var _id = ObjectId.generate()
#objc dynamic var name = "Jay"
let dogList = List<DogClass>()
override static func primaryKey() -> String? {
return "_id"
}
}
and then our DogClass has an inverse relationship to the PersonClass objects
class DogClass: Object {
#objc dynamic var _id = ObjectId.generate()
#objc dynamic var name = ""
let linkingOwners = LinkingObjects(fromType: PersonClass.self, property: "dogList")
override static func primaryKey() -> String? {
return "_id"
}
}
Then suppose we want to observe Spot's linkingOwners - both Jay and Cindy had Spot added to their dogList previously
let spot = realm.objects(DogClass.self).filter("name == 'Spot'").first!
self.peopleToken = spot.linkingOwners.observe { changes in
switch changes {
case .initial(let dogs):
print(" spots owners have been loaded")
case .update(_, let deletions, let insertions, let modifications ):
print(" something changed in spots owners")
case .error(let error):
print(error.localizedDescription)
}
}
Running this section of code outputs this to console and adds the observer the linkingObjects
spots owners have been loaded
Then, lets make a change to one of the owners properties
let jay = realm.objects(PersonClass.self).filter("name == 'Jay'").first!
try! realm.write {
jay.name = "Jay, Spots owner"
}
that last piece of code will output this to the console
something changed in spots owners
The above code creates a PersonClass object and a DogClass object object with a inverse relationship. The code then adds an observer the linkingObjects (PersonClass) and fires when one of them changes.
Turns out the linking objects now have to be declared like so:
class Y: Object {
...
#Persisted(originProperty: "y") var xxx: LinkingObjects<X>
...
}
I am not sure if the declaration style I used in my question is still supposed to be valid and if this is a bug, but using the new style gets rid of the exception.

How to add variable in existing class in swift?

I know that in swift we can use Extensions to add new methods to existing classes.
But what about if i want to add a variable?
extension UIViewController {
var myVar = "xyz"
}
It gives like :
Extensions must not contain stored properties
We can't add the stored properties to extensions directly but we can have the computed variables.
extension UIViewController {
var myVar: String {
return "xyz"
}
}
Extensions in Swift can:
Add computed instance properties and computed type properties
...
For more please visit
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
You can only add computed properties to extensions as follows...
extension UIViewController {
var someProperty = "xyz" : String {
return "xyz"
}
}
If you wish to use it the way you are defining it, you might need to subclass your UIViewController
class YourCustomViewController: UIViewController {
var someProperty: String = "xyz"
}
you can only use computed variables:
for example we have the type Int in swift, and we want it extend in a way that swift generates a random number from 0 to our number :
extension Int
{
var arc4random : Int{
if self > 0
{return Int(arc4random_uniform(UInt32(UInt(self))))}
else if self < 0
{return -Int(arc4random_uniform(UInt32(UInt(abs(self)))))}
else
{return 0}
}
}
and usage :
myArray.count.arc4random
here my array.count is an Int , and arc4random is the computed variable we have defined in our extension, u cant store a value in it
You can try ( This is a readOnly computed property )
extension UIViewController {
var someProperty : String {
return "xyz"
}
}

Can we add static stored variable via extension, in Swift?

In the book Swift Programming Language 3.0, it says that we can't use extension to add stored property.
I tried it out with instance stored variable and Xcode displayed an error as expected.
But when I tried with static stored variable, everything compiled just fine.
Is there something that I'm missing or doing wrong?
class MyClass {}
extension MyClass {
static var one: Int {
return 1
}
static var two = 2 //compiled just fine
}
let myVariable = MyClass()
MyClass.two
You can't put stored properties in instances of an extension, you can cheat a little though and get the same effect with Objective-C associated objects. Give the following code a try:
private var associationKey: UInt8 = 0
var validationTypes: ValidationTypes {
get {
return objc_getAssociatedObject(self, &associationKey) as? ValidationTypes ?? []
}
set(newValue) {
objc_setAssociatedObject(self, &associationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
Obviously replacing ValidationTypes as appropriate.

Using custom model class with Backendless in Swift

I'm trying to retrieve data from an online data storage using the func that I found online on the official Backendless docs! but when I try to use persona like a Lista(my own class) Object, I get the error: Could not cast value of type '__NSDictionaryM' (0x10c1ccfc0) to 'InLIsta_.Lista' (0x108439790).
I search over this site but the answer aren't specific for the Backendless case, so I hope that anyone can help me
this is my code (obviously I've declared all the var and let necessary to the code to run):
class Lista : NSObject {
var nome: String?
var pr: String?
var pagamento = 0
var entrato: Bool = false
var commenti: String?
var objectId: String?
var created: NSDate?
var updated: NSDate?
}
func findQ() {
Types.tryblock({ () -> Void in
let startTime = NSDate()
let found = self.backendless.persistenceService.of(Lista.ofClass()).find(self.query)
let currentPage = found.getCurrentPage()
print("Loaded \(currentPage.count) name objects")
print("Total name in the Backendless storage - \(found.totalObjects)")
for person in currentPage {
let persona = person as! Lista // here i get error
print("Restaurant <\(Lista.ofClass())> name = \(persona.nome)")
self.nomi.append(persona.nome!)
}
print("Total time (ms) - \(1000*NSDate().timeIntervalSinceDate(startTime))")
},
catchblock: { (exception) -> Void in
print("Server reported an error: \(exception as! Fault)")
}
)
}
The backendless persistence service has a method -(void)mapTableToClass:(NSString *)tableName type:(Class)type; that you need to call for each of your custom classes so they'll be used during the deserialisation.
self.backendless.persistenceService.mapTableToClass("Lista", type: Lista.self)
This needs to be done before any calls are made to use the persistence service.
Note that the classes, if not defined in obj-c, must be exported to obj-c. Note that this also means you can't have any optionals.
Ideally you should use the platform code generation to create your model class definitions to ensure all of the attributes are created with the appropriate types. A failure to map to your custom class could be caused by type mismatches or name mismatches. Optionals will always fail in the current SDK implementation.

Create a Swift Object from a Dictionary

How do you instantiate a type dynamically based upon a lookup value in a dictionary in Swift?
Hopefully this is useful to others. It took some research to figure this out. The goal is to avoid the anti-pattern of giant if or switch statements to create each object type from a value.
class NamedItem : CustomStringConvertible {
let name : String
required init() {
self.name = "Base"
}
init(name : String) {
self.name = name
}
var description : String { // implement Printable
return name
}
}
class File : NamedItem {
required init() {
super.init(name: "File")
}
}
class Folder : NamedItem {
required init() {
super.init(name: "Folder")
}
}
// using self to instantiate.
let y = Folder.self
"\(y.init())"
let z = File.self
"\(z.init())"
// now put it in a dictionary.
enum NamedItemType {
case folder
case file
}
var typeMap : [NamedItemType : NamedItem.Type] = [.folder : Folder.self,
.file : File.self]
let p = typeMap[.folder]
"\(p!.init())"
let q = typeMap[.file]
"\(q!.init())"
Interesting aspects:
use of "required" for initializers
use of .Type to get the type for the dictionary value.
use of .self to get the "class" that can be instantiated
use of () to instantiate the dynamic object.
use of Printable protocol to get implicit string values.
how to init using a non parameterized init and get the values from subclass initialization.
Updated to Swift 3.0 syntax

Resources