Delete Realm Object By Value - swift

I started trying Realm for IOS, so I created two classes:
Files Model
import Foundation
import RealmSwift
class FilesModel: Object {
#objc dynamic var id : Int = 0
#objc var fileName = ""
#objc dynamic var dateOfCreation = Date()
#objc dynamic var dateOfModification = Date()
#objc dynamic var type = ""
var file = List<Data>()
}
Groups Model
import Foundation
import RealmSwift
class GroupsModel: Object {
#objc dynamic var id : Int = 0
#objc dynamic var name = ""
#objc dynamic var dateOfCreation = Date()
#objc dynamic var dateOfModification = Date()
#objc dynamic var filesCount = Int()
var files = List<FilesModel>()
override static func primaryKey() -> String? {
return "id"
}
}
Now the thing is I am copying files into groups model file Object but I need to delete the parent object.
think of it as a move I am moving files into the folder.
what I have done is I save a copy of the file into the folder and delete the file from outside the folder.
Problem
when I delete the file outside the folder it will also delete the file inside.
My understanding of the problem
classes is a reference type so I am copying reference. So when I delete the reference it will delete the file from the whole project.
I have tried many solutions like deep copy and detached.
Thanks in Advance.

The issue is this statement
I am moving files into the folder
While that may be what you want to do, the objects you're moving aren't actually being moved. When you add a managed object to a a List property, it adds a reference to the object, not the object itself.
In other words, when a FilesModel is added to a GroupsModel files List property, it's a reference to the object. If you delete the FilesModel, it will also be gone from the List. But, removing it from the List does not change the original object.
However, Lists can also contain Embedded Objects - an embedded object only ever exists within it's parent object. Perhaps that would be an option?
So like this. Here's a couple of models
class FileModel: EmbeddedObject {
#Persisted var fileName = ""
}
class GroupsModel: Object {
#Persisted var files = List<FilesModel>()
}
Then instantiate a group and add a couple of file objects to it
let group = GroupsModel()
let f0 = FileModel()
f0.fileName = "some filename"
let f1 = FileModel()
f1.fileName = "another filename"
group.files.append(objectsIn: [f0, f1])
results in a group with two files that only ever appear within that group.
Another option is to simply make a copy of the object
let objectCopy = MyObject(value: objectToCopy)
and then add the objectCopy to your Groups model. But again, by doing that Realm will instantiate the objectCopy and actually add it back to Realm (possibly overwriting the original object).

Related

How can I let the user add an attachment to my app like a pdf or jpg and then how can I store it in my Realm Database?

Here is my code for my object that I am storing in Realm Database
class Accomp2: Object {
#objc dynamic var title: String = ""
#objc dynamic var date: Date!
#objc dynamic var month:String = ""
required init() {
}
#objc dynamic var body:String = ""
#objc dynamic var type:String = "Professional"
#objc dynamic var identifier:String = ""
}
I want to be able to store the attachment in a variable called attachment, but I am not sure what type of variable that is.
With the object, I want to be able to show this attachment on a view controller as a picture.
If this is not possible with Realm Database, is there another way to store attachments?
See the Realm property Cheat Sheet
What you want is the NSData() e.g. Swift Data() object - he's some simple code as a conceptual example.
let url = //your file
let myData = Data(contentsOf: url) //please handle the optional correctly
class Accomp2: Object {
#objc dynamic var acc_id = UUID().uuidString
#objc dynamic var name = ""
#objc dynamic var value = Data()
}
let x = Accomp2()
x.name = "Some name"
x.value = myData
IMPORTANT!
While you can do this, you probably shouldn't.
Realm is not well suited for handling documents within objects. If it's a thumbnail or a couple hundred kb, it will be ok. But PDF's can get HUGE and Realm is not the right solution.
You should store files in another source that's designed for storing files - Firebase Cloud Storage is one such option and then store the URL to the file within your Realm object.

Trouble binding a data class that has numerous String, Bool and Array properties. Using Xcode 9.4.1 with Swift 4.2 for macOS

I am trying to create a macOS project using Xcode 9.4.1 with Swift 4.2. I am using a Document-Based Application since I am entering data. The project has a class that includes an array as a property along with other properties. This class will be used to enter data that will need to persist and I'm trying to use IB and bindings to get this to work.
Here is the class (The actual class has much more String, Bool and Array properties):
class MyClass: NSObject {
#objc dynamic var property1 = ""
#objc dynamic var property2 = true
#objc dynamic var property3 = true
#objc dynamic var myClass2s: [myClass2] = []
}
class myClass2: NSObject {
#objc dynamic var property4 = ""
#objc dynamic var property5 = ""
}
I can get a tableView with an arrayController to work for the String and Bool properties. The difficulty for me comes in when I need to have another tableView for the MyClass2 data to be entered, which requires another arrayController. I can't seem to figure out how to bind it all together.
EDIT 9/30
I've tried binding the details tableView's Table Content to MyClassArrayController, Controller Key: selection, Model Key Path: myClass2s. I have a second Array Controller for MyClass2 so I can add/remove data to MyClass2. When I run the project, I don't get any errors, however, I can't add data to MyClass2 objects with its table View content bound to the array myClass2s.
So, in addition to what I tried above, I bound MyClass2ArrayController's Content Array to MyClassArrayController, selection, myClass2s and so far it appears to be working now.

Creating a global variable in swift

I am trying to create a global variable from my view controller (inside the class but outside the functions) as follows:
var modelData: CustomTabBarController.model // THE ERROR IS HERE
This is how that class is defined:
CustomTabBarController.swift:
import UIKit
// This class holds the data for my model.
class ModelData {
var name = "Fred"
var age = 50
}
class CustomTabBarController: UITabBarController {
// Instantiate the one copy of the model data that will be accessed
// by all of the tabs.
var model = ModelData()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
However I am getting the following error:
"'model' is not a member type of "CustomTabBarController"
How do I declare it so that I can access model? Thanks.
Update #1
Sorry I forgot to mention this:
I need the model data to be the SAME in every tab of the tabbar. For example if I change the age to 51 in the first tab, the second tabbar should retrieve 51. Which would be the correct method above to use it this way?
Update #2
I am able to create the variable inside a function with dean's suggestion:
func setupModelData()
{
var modelData = (self.tabBarController as! CustomTabBarController).model
}
However this does not work, since I need to access the modelData from other functions. When I attempt to move this line outside of the function as follows:
import UIKit
class FirstViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
var modelData = (self.tabBarController as! CustomTabBarController).model
...
I receive the error:
Value of type '(NSObject) -> () -> FirstViewController' has no member 'tabBarController'
I ended up following holex's suggestion of creating a shared class (singleton):
import UIKit
class ModelData: NSObject {
static let shared: ModelData = ModelData()
var name = "Fred"
var age = 50
}
Writing in first view: Set age to 51:
ModelData.shared.age = 51
Reading in second view: Get age of 51
let age = ModelData.shared.age
I'm not sure whether you truly want a global variable (i.e. a single instance of ModelData shared between all your view controllers) or an instance variable which is public, so I'll try to answer both :)
1) global model
This line attempts to get the model property from the CustomerTabBarController class - i.e. if you made multiple tab bar controllers they would all use the same model.
var modelData: CustomTabBarController.model
If this is what you want, then you need to change this line to include the static keyword.
static var model = ModelData()
However, this almost certainly isn't what you're after.
2) shared instance variable
This means that the model is part of each instance of CustomTabBarController. Here, you would need to change the line which is throwing the error to be something like this:
var modelData: myCustomTabBarController.model
Without knowing more about your architecture, I can't help you get hold of your tab bar controller instance, but something like this might work (inside other view controllers):
var modelData = (self.tabBarController as! CustomTabBarController).model
model is an instance variable.
Either create an instance of CustomTabBarController
var modelData = CustomTabBarController().model
Or declare model as class variable
static var model = ModelData()
...
var modelData = CustomTabBarController.model
However to use ModelData as a single global variable with the two members, use a struct rather than a class and declare the members as static.
struct ModelData {
static var name = "Fred"
static var age = 50
}
You can access the name from everywhere for example
let name = ModelData.name
and there is no need to create an extra variable in another class.
An – instance based –  alternative is a singleton
struct ModelData {
static let shared = ModelData()
var name = "Fred"
var age = 50
}
and use it
let name = ModelData.shared.name

Realm - Property cannot be marked dynamic because its type cannot be represented in Objective-C

I am trying to implement below scenario, but i am facing the issue
class CommentsModel: Object {
dynamic var commentId = ""
dynamic var ownerId: UserModel?
dynamic var treeLevel = 0
dynamic var message = ""
dynamic var modifiedTs = NSDate()
dynamic var createdTs = NSDate()
//facing issue here
dynamic var childComments = List<CommentsModel>()
}
I have a comments model which has non optional properties in which childComments is List of same Comments model class. In this when i declare dynamic var childComments = List<CommentsModel>()
it shows me Property cannot be marked dynamic because its type cannot
be represented in Objective-C.
Please help me how to achieve my requirement
List and RealmOptional properties cannot be declared as dynamic because generic properties cannot be represented in the Objective‑C runtime, which is used for dynamic dispatch of dynamic properties, and should always be declared with let.
Learn more in Docs.
So you should declare childComments this way:
let childComments = List<CommentsModel>()
Just to make it more understandable how you can add data to the list although its declared as let.
import Foundation
import RealmSwift
import Realm
class Goal: Object {
//List that holds all the Events of this goal
let listOfEvents = List<CalEvent>()
required public convenience init(eventList: List<CalEvent>) {
self.init()
for event in eventList {
//Append the date here
self.listOfEvents.append(i)
}
}
}

Delete a Realm model with Swift

I need to remove old, empty models from a Realm Cocoa database.
There seems to be a way to do it in Java, but not in Swift. Is that correct?
If you remove a property and initiate a migration Realm will remove the corresponding column in the table:
class Dog: Object {
dynamic var name = ""
// dynamic var age = 0
}
But, if you remove the model definition entirely, the migration does not remove the table:
// class Dog: Object {
// dynamic var name = ""
// dynamic var age = 0
// }
Here's a screenshot from Realm Browser showing the empty tables I want to delete:
You can call Migration.deleteData(_:) within your migration block to specify that the named class should be completely removed from your Realm file.
For those who are working on JavaScript:
migration: (oldRealm, newRealm) => {
if (oldRealm.schemaVersion < *version*) {
newRealm.deleteModel('MODEL-NAME')
}
}