Search code examples
iosswiftrealm

iOS RealmSwift storage with Swift 4


I am trying to use RealmSwift in order to save items to the phone storage in Swift 4. I have two different Views; one for the save functionality and another which will display all saved items into a TableView. I have a buildable form coded but i am throwing an error Thread 1: signal SIGABRT specifically on the line when i call realm.add. When i am in my view which is saving, i am using a IBAction with a button to initiate the save functionality. Can anyone help me with this issue? I think the issue is when i set the var of realm however i am unsure.


UPDATE:

I have changed my implementation to reflect the idea given in this thread about my original issue. After doing so, when the call to add the item to the realm is called i crash EXC_BAD_ACCESS (code=EXC_I386_GPFLT) inside the source code of the API. Specifically I crash at this function of the API

//CODE EXCERPT FROM REALMSWIFT API 

// Property value from an instance of this object type
id value;
if ([obj isKindOfClass:_info.rlmObjectSchema.objectClass] && 
prop.swiftIvar) {
    if (prop.array) {
        return static_cast<RLMListBase *>(object_getIvar(obj, 
prop.swiftIvar))._rlmArray;
    }
    else { // optional
        value = static_cast<RLMOptionalBase *>(object_getIvar(obj, 
prop.swiftIvar)).underlyingValue; //CRASH OCCURS HERE!!!!!!!!
    }
}
else {
// Property value from some object that's KVC-compatible
    value = RLMValidatedValueForProperty(obj, [obj 
respondsToSelector:prop.getterSel] ? prop.getterName : prop.name,

_info.rlmObjectSchema.className);
}
return value ?: NSNull.null;

import UIKit
import RealmSwift

class DetailsViewController: UIViewController {

var titleOfBook: String?
var author: String?

@IBAction func SavetoFavorites(_ sender: Any) {
    DispatchQueue.global().async { [weak self] in
guard let strongSelf = self else { return }
guard let realm = try? Realm() else {
  return
}

let newItem = Favorites()
newItem.title = strongSelf.titleOfBook
newItem.author = strongSelf.author

try? realm.write {
  realm.add(newItem) // Crashes on this line
}
}
}

import UIKit
import RealmSwift

final class Favorites: Object {
var title: String?
var author: String?
}

class FavoritesTableViewController: UITableViewController {

var items: Array<Favorites> = []

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(UITableViewCell.self, forCellReuseIdentifier: 
"cell")
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    tableView.reloadData()
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

override func numberOfSections(in tableView: UITableView) -> Int {
    return 0
}

override func tableView(_ tableView: UITableView?, 
numberOfRowsInSection section: Int) -> Int {
    return items.count
}

override func tableView(_ tableView: UITableView, cellForRowAt 
indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", 
for: indexPath)
    let item = items[indexPath.row]
    cell.textLabel?.text = item.title
    cell.detailTextLabel?.text = item.author
    return cell
}

var selectedIndexPath: NSIndexPath = NSIndexPath()

override func tableView(_ tableView: UITableView, willSelectRowAt 
indexPath: IndexPath) -> IndexPath? {
    selectedIndexPath = indexPath as NSIndexPath
    return indexPath
}

Solution

  • You have to wrap realm.add(newItem) inside a transaction:

    try! realm.write {
      realm.add(newItem)
    }
    

    Please note, that write transactions block the thread they are made on so if you're writing big portions of data you should do so on background thread (realm has to be instantiated on that thread too). You could do it like this:

    @IBAction func saveToFavorites(_ sender: Any) {
      DispatchQueue.global().async { [weak self] in
        guard let strongSelf = self else { return }
        guard let realm = try? Realm() else {
          // avoid force unwrap, optionally report an error
          return
        }
    
        let newItem = Favorites()
        newItem.title = strongSelf.titleOfBook
        newItem.author = strongSelf.author
    
        try? realm.write {
          realm.add(newItem)
        }
      }
    }
    

    Update: I haven't noticed that you have an issue with your model too – since Realm is written with Objective C you should mark your model properties with @objc dynamic modifiers:

    final class Favorites: Object {
      @objc dynamic var title: String?
      @objc dynamic var author: String?
    }