saving array into realm database swift - swift

I have an application which uses realm database to persist data and everything works fine but the issue I have now is I want to save photo: Data array to the database and I tried using the standard swift array format but got an error at build time. below is my code
class TodoListModel: Object {
#objc dynamic var id = UUID().uuidString
#objc dynamic var photo: Data? = nil
#objc dynamic var createdDate: Date?
override static func primaryKey() -> String? {
return "id"
}
let parentCategory = LinkingObjects(fromType: CategoryModel.self, property: "items")
}
how do I now make the photo into an array
this is the way I create my List
func createTodoList(createdDate: Date, photo: Data) -> Void {
let todoList = TodoListModel()
todoList.createdDate = createdDate
todoList.photo = photo
TodoListFunctions.instance.addData(object: todoList)
}
update model
func updateTodoList(update: TodoListModel, createdDate: Date, photo: Array<Data>) -> Void {
update.createdDate = createdDate
update.photo.append(objectsIn: photo)
}

To be able to store several objects of type Data in a single property of an Object subclass, you need to use List.
class TodoListModel: Object {
#objc dynamic var id = UUID().uuidString
#objc dynamic var createdDate: Date?
let photos = List<Data>()
let parentCategory = LinkingObjects(fromType: CategoryModel.self, property: "items")
override static func primaryKey() -> String? {
return "id"
}
}
Then you can create a TodoListModel instance like this:
func createTodoList(createdDate: Date, photos: Array<Data>? = nil) -> Void {
let todoList = TodoListModel()
todoList.createdDate = createdDate
if let photos = photos {
todoList.photos.append(objectsIn: photos)
}
TodoListFunctions.instance.addData(object: todoList)
}

Related

Fetch a string from core data and print it

I am trying to fetch a core data string from binary data. I am trying to use func getText to do this but I am getting an error stating Type of expression is ambiguous without more context at let imageData = Person[textNo].name!. I also have the singleton. I would like to print ideally the first saved name in core in the debug section. The data saves fine.
extension Person {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Person> {
return NSFetchRequest<Person>(entityName: "Person")
}
#NSManaged public var name: String?
#NSManaged public var ssn: Int16
}
class ViewController: UIViewController {
func getText(textNo:Int) {
// first check the array bounds
let info = helpText.shareInstance.fetchText()
if info.count > textNo {
if let imageData = Person[textNo].name!
{
print(imageData)
} else {
// no data
print("data is empty Textss")
}
} else {
// image number is greater than array bounds
print("you are asking out of bounds")
}
}
//insert
func save(name: String, ssn : Int16) {
let person = CoreDataManager.sharedManager.insertPerson(name: name, ssn: ssn)
if person != nil {
people.append(person!)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
save(name: "joe", ssn: 3343)}

Deleting Objects with subclasses in Swift Realm

I have a really simple database in Swift Realm for a todo app:
Items and their parent Categories.
The user can delete both the Items and the Categories with a simple swipe action. The action works fine, there are no issues when deleting Items. If I delete a Category, that works too, but I can still see the Items in the Realm Browser, those remain in the database even though there are no parent anymore. Obviously the user can't see these, they are doing nothing but still, it would be better to get rid of these with the parent Category. Are there any simple ways to do this?
class Category: Object{
#objc dynamic var name: String = ""
#objc dynamic var color: String = ""
#objc dynamic var order = 0
let items = List<Item>()
override static func primaryKey() -> String? {
return "order"
}
static func incrementalIDCat() -> Int {
let realm = try! Realm()
return (realm.objects(Category.self).max(ofProperty: "order") as Int? ?? 0) + 1
}
}
class Item: Object {
#objc dynamic var title: String = ""
#objc dynamic var done: Bool = false
#objc dynamic var dateCreated: Date?
#objc dynamic var order = 0
var parentCategory = LinkingObjects(fromType: Category.self, property: "items")
override static func primaryKey() -> String? {
return "order"
}
static func incrementalIDItem() -> Int {
let realm = try! Realm()
return (realm.objects(Item.self).max(ofProperty: "order") as Int? ?? 0) + 1
}
}
override func updateModel(at indexPath: IndexPath) {
if let categoryForDeletion = self.categories?[indexPath.row] {
do {
try self.realm.write {
self.realm.delete(categoryForDeletion)
}
} catch {
print("Error deleting category, \(error)")
}
}
tableView.reloadData()
}
You just delete items first.
self.realm.delete(categoryForDeletion.items)
self.realm.delete(categoryForDeletion)
Or, with this extension, you can do this.
self.realm.delete(categoryForDeletion, cascading: true)

Get notified when value in List is updated using realm

I am trying to write an application in OS X using a Realm database. I want to trigger notification when where there is change in value of List which is inside another object
Below is the Class
final class Profile: Object {
#objc dynamic var gradient1 = ""
#objc dynamic var gradient2 = ""
#objc dynamic var fontColor = ""
#objc dynamic var selectedFont = ""
#objc dynamic var selectedTitleFont = ""
#objc dynamic var fontFamily = ""
#objc dynamic var name = ""
#objc dynamic var shortbio = ""
#objc dynamic var avatarSource = ""
#objc dynamic var userid = ""
#objc dynamic var email = ""
var features = List<Features>()
var socialLinkButtons = List<SocialLinkButtons>()
#objc dynamic var appSelectedMetaData : AppMetaData? = nil
override static func primaryKey() -> String?{
return "userid"
}
}
final class Features: Object {
#objc dynamic var uuid = ""
#objc dynamic var id = ""
#objc dynamic var label = ""
#objc dynamic var screen = ""
#objc dynamic var active = false
override static func primaryKey() -> String?{
return "id"
}
convenience init(id: String, uuid: String, label: String, screen: String, active: Bool) {
self.init()
self.id = id
self.uuid = uuid
self.label = label
self.screen = screen
self.active = active
}
}
I want to trigger notifications whenever value inside feature is updated.
You can use Realm Collection Notifications to achieve your goals. You just need to make sure that you store the returned NotificationToken in a variable that doesn't get deallocated until you don't actually need to receive the notifications anymore and that you call .invalidate() on the token when you no longer want to receive notifications.
func observeFeatureChanges(in profile:Profile) -> NotificationToken {
let notificationToken = profile.features.observe { changes in
switch changes {
case .update(_, deletions: let deletionIndices, insertions: let insertionIndices, modifications: let modIndices):
print("Objects deleted from indices: \(deletionIndices)")
print("Objects inserted to indices: \(insertionIndices)")
print("Objects modified at indices: \(modIndices)")
case .error(let error):
print(error)
case .initial(let type):
print(type)
}
}
return notificationToken
}

Filter is returning all children for parent with matching child

I'm using Realm for Swift and I have a structure as follows:
class Navigation: Object {
dynamic var key = 0
dynamic var title: String?
let companies = List<Companies>()
override static func primaryKey() -> String? {
return "key"
}
}
class Companies: Object {
dynamic var key = 0
dynamic var name: String?
let locations = List<Locations>()
override static func primaryKey() -> String? {
return "key"
}
}
class Locations: Object {
dynamic var key = 0
...
dynamic var zip: String?
let contacts = List<Contacts>()
override static func primaryKey() -> String? {
return "key"
}
}
class Contacts: Object {
dynamic var key = 0
dynamic var firstName: String?
dynamic var lastName: String?
...
override static func primaryKey() -> String? {
return "key"
}
}
I'm trying to filter out locations by zip code, so that only locations that match the given zip code are displayed. I'm doing that like this
companies = realm.objects(Navigation.self).filter("key = 4").first!.companies.filter(predicate).sorted(byKeyPath: "key")
The key = 4 bit is because the filter is only supposed to search in companies under one specific category.
The problem that I'm having is that it returns all locations for a company that has a matching location. So if my zip to find is 12345, and companyA has a location that matches, all the locations under companyA are returned, even if they aren't a match.
How can I limit the results to be only locations with a match?
How can I limit the results to be only locations with a match?
Right now you're returning a Results<Companies>, but it seems like you want locations. I accomplished what I think you're looking for by adding some inverse relationship properties to the Companies and Locations models, and then queried the Realm for Locations matching zip == '12345' && ANY parentCompanies.parentNavigation.key == 4.
Here's a sample app that demonstrates this:
import UIKit
import RealmSwift
class Navigation: Object {
dynamic var key = 0
dynamic var title: String?
let companies = List<Companies>()
override static func primaryKey() -> String? {
return "key"
}
}
class Companies: Object {
dynamic var key = 0
dynamic var name: String?
let locations = List<Locations>()
let parentNavigation = LinkingObjects(fromType: Navigation.self, property: "companies")
override static func primaryKey() -> String? {
return "key"
}
}
class Locations: Object {
dynamic var key = 0
// ...
dynamic var zip: String?
let contacts = List<Contacts>()
let parentCompanies = LinkingObjects(fromType: Companies.self, property: "locations")
override static func primaryKey() -> String? {
return "key"
}
}
class Contacts: Object {
dynamic var key = 0
dynamic var firstName: String?
dynamic var lastName: String?
// ...
override static func primaryKey() -> String? {
return "key"
}
}
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
_ = try? FileManager.default.removeItem(at: Realm.Configuration.defaultConfiguration.fileURL!)
let realm = try! Realm()
// Objects Matching Query
try! realm.write {
// Locations
let locations = Locations()
locations.zip = "12345"
// Companies
let companies = Companies()
companies.name = "Companies A"
companies.locations.append(locations)
// Nav
let nav = Navigation()
nav.key = 4
nav.companies.append(companies)
// Add to Realm
realm.add(nav)
}
let locationsIn12345AndNavigationKey4 = realm.objects(Locations.self)
.filter("zip == '12345' && ANY parentCompanies.parentNavigation.key == 4")
print(locationsIn12345AndNavigationKey4)
return true
}
}
This prints:
Results<Locations> (
[0] Locations {
key = 0;
zip = 12345;
contacts = RLMArray <0x6000000f2100> (
);
}
)

Saving custom object as core data property

I am trying to save a custom class as a property of a core data object.
The Core Data object:
#objc(Safer)
class Safer: NSObject
{
#NSManaged var perakimFiles: [prayer]? //This line gives me an error saying that it cannot save a type that is not Obj. C
#NSManaged var titleEnglish: String?
#NSManaged var titleHebrew: String?
#NSManaged var parshaPerakim: [Int]?
#NSManaged var saferCode: String?
var titles: [[String]]
{
get
{
var ret = [[String]]()
var i = 0
for file in perakimFiles!
{
ret.append([file.title, "\(i+1)"])
i++
}
return ret
}
}
init(_ _saferCode: SefarimCodes)
{
super.init()
self.saferCode = _saferCode.rawValue
}
init(_perakimFiles: [prayer], _titleEnglish: String, _titleHebrew: String)
{
super.init()
self.perakimFiles = _perakimFiles
self.titleEnglish = _titleEnglish
self.titleHebrew = _titleHebrew
}
init(_perakimFiles: [prayer], _titleEnglish: String, _titleHebrew: String, _parshaPerakim: [Int])
{
super.init()
self.perakimFiles = _perakimFiles
self.titleEnglish = _titleEnglish
self.titleHebrew = _titleHebrew
self.parshaPerakim = _parshaPerakim
self.saferCode = setTorahSaferCode()!.rawValue
let config = self.configFromCode()
self.perakimFiles = config.perakimFiles
}
}
Here is the prayer class that I am trying to save in the core data object:
class prayer
{
var url: NSURL
var title: String
var detail: String?
init(initURL: NSURL, initTitle: String)
{
print("1")
print("2")
self.title = initTitle
print("3")
self.url = initURL
print("4")
}
init(initURL: NSURL, initTitle: String, initDetail: String)
{
self.url = initURL
self.title = initTitle
self.detail = initTitle
}
}
So what can I do to the prayer class to make it savable by the core data object? I need to also be able to use instances of the prayer class in other places of the code.
As mentioned, have your prayer class subclass NSObject and conform to NSCoding which requires two methods : -initWithCoder: and encodeWithCoder:
Once those are implemented, you can use NSKeyedArchiver/NSKeyedUnarchiver class methods to transform your objects into NSData objects and back, thus allowing you to store your objects as CoreData properties under the supported NSData type.
Let class prayer conforms to NSObject and NSCoding and see whether that addresses the error.