Reputation: 1514
I have a UIView where i want to update my ui after i received and parse the json from the backend. I use a generic API manager so my callback is called too soon. My workaround and the best practice i think would be to use a realm notification block. The notification block is called once on viewDidLoad but the update is not called even though i modify a realm object property after the parsing of the json. Sample of code for the view :
import SwiftyJson
import RealmSwift
var notificationToken: NotificationToken?
var article: Article?
if let result = Article.getLocalArticle(article!.id) {
// Observe Notifications on article from Network
notificationToken = result.addNotificationBlock { [weak self] (changes: RealmCollectionChange) in
switch changes {
case .Initial:
break
case .Update:
print("updating")
self!.updateView()
case .Error(let error):
// An error occurred while opening the Realm file on the background worker thread
fatalError("\(error)")
break
}
}
}
Sample for the realm object :
import SwiftyJson
import RealmSwift
public class Article : Object {
dynamic var liked = false
dynamic var id = String()
override public static func primaryKey() -> String? {
return "id"
}
// MARK: – Create article method
public class func article(json: JSON) -> Article? {
let article = Article()
if let id = json["id"].string {
article.id = id
}
if let liked = json["liked"].bool {
article.liked = liked
}
return article
}
// parse response Json for only one article after getting articleDetail
public class func parseUpdateArticleJson(json: JSON) {
//print(json)
do {
let realm = try Realm()
realm.beginWrite()
let article = self.article(json)
realm.add(article!, update: true)
try realm.commitWrite()
} catch {
print(error)
}
}
public class func getLocalArticle(articleId: String) -> Results<Article>? {
do {
let realm = try Realm()
let result = realm.objects(Article.self).filter("id == %@", articleId)
return result
} catch {
print(error)
}
return nil
}
}
After a tap on the like button in my view i send the action to the backend which will update my realm object setting the liked property to true (or false if it was true). The expected behaviour is for the notification block to call the updateView method when the like property on my realm object is updated. Any hint would be welcome
Upvotes: 0
Views: 1071
Reputation: 1262
Alright so the issue is how you're adding the object to Realm. You can only set update
to true in realm.add(article!, update: true)
when a primary key exists. The update property tells realm to intelligently update the Realm object based on it's primary key (or just add it if it doesn't exist).
Check this out for more info: https://realm.io/docs/swift/latest/#creating-and-updating-objects-with-primary-keys
The reason it's failing is because Realm throws an exception when you are doing realm.add(article!, update:true)
with this error:
Terminating app due to uncaught exception 'RLMException', reason: ''Article' does not have a primary key and can not be updated'
And your do/catch block catches the error. The object never gets added to realm and the notification block never gets notified. That's my assumption right now as to why it's failing. However, I see that you are printing out the error so maybe you caught this already.
So what you can do is assign a primary key to your Article object by doing this:
public class Article : Object {
dynamic var liked = false
dynamic var id = String()
override static func primaryKey() -> String? {
return "id"
}
}
Or if you don't want your id
property to be a primary key (i.e. unique) then you can add the object by doing this: realm.add(article)
. The default value of update will be false. Which means it will always add (and never update), even if an object exists with the same primary key.
Upvotes: 1