How to list LinkingObjects properties in Realm? - swift

I need to list all properties of type LinkingObjects of a object.
class Dogs: Object {
dynamic var name: String = ""
dynamic var age: Int = 0
dynamic var owner: Persons?
}
class Cats: Object {
dynamic var name: String = ""
dynamic var age: Int = 0
dynamic var owner: Persons?
}
class Persons: Object {
dynamic var name: String = ""
dynamic var address: String = ""
let dogs = LinkingObjects(fromType: Dogs.self, property: "owner")
let cats = LinkingObjects(fromType: Cats.self, property: "owner")
}
ObjectSchema returns the schema correctly:
let person = Persons()
let schema = person.objectSchema
print(schema)
Result:
Persons {
name {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}
address {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}
dogs {
type = linking objects;
objectClassName = Dogs;
linkOriginPropertyName = owner;
indexed = NO;
isPrimary = NO;
optional = NO;
}
cats {
type = linking objects;
objectClassName = Cats;
linkOriginPropertyName = owner;
indexed = NO;
isPrimary = NO;
optional = NO;
}
}
However, objectSchema.properties does not return LinkingObjects properties.
let properties = schema.properties
print(properties)
Returns:
[name {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}, address {
type = string;
objectClassName = (null);
linkOriginPropertyName = (null);
indexed = NO;
isPrimary = NO;
optional = NO;
}]
Where are the dogs and cats properties?
Thanks.

I found the solution:
let computedProperties = Persons.sharedSchema()?.computedProperties

The LinkingObjects properties are listed in the computedProperties property of RLMObjectSchema, which is currently not public or present on the Swift version of the class. While it's possible to get to the private property given an instance of the obj-c class (via .valueForKey("computedProperties")), that won't work on the Swift ones and there isn't any good way to get to the obj-c RLMObjectSchema when using Realm Swift.
There's an existing feature request to expose this.

Related

Deep copy of array with elements containing an array?

I'm trying to make a deep copy of a list of the following objects:
struct Book {
var title: String
var author: String
var pages: Int
}
struct BookShelf {
var number: Int
}
class BookShelfViewModel {
var bookShelf: BookShelf
var number: Int
var books: [BookViewModel]?
init(bookShelf: BookShelf) {
self.bookShelf = bookShelf
self.number = bookShelf.number
}
required init(original: BookShelfViewModel) {
self.bookShelf = original.bookShelf
self.number = original.number
}
}
class BookViewModel {
var book: Book
var title: String
var author: String
var pages: Int
init(book: Book) {
self.book = book
self.title = book.title
self.author = book.author
self.pages = book.pages
}
required init(original: BookViewModel) {
self.book = original.book
self.title = original.title
self.author = original.author
self.pages = original.pages
}
}
Books for BookShelf is fetched in the BookShelfViewModel.
If I go like:
var copiedArray = originalArray
for bs in copiedArray {
bs.books = bs.books.filter { $0.title == "SampleTitle" }
}
The above filter both the copiedArray and the originalArray, and I obviously just want the copiedArray altered.
When I clone the array like this:
var originalArray = [BookShelfViewModel]()
... // Fill the array
var clonedArray = originalArray.clone()
clonedArray is cloned, but clonedArray.books is empty.
I've created the extension and followed this gist. How do I clone the array in the objects in the array?
I've done a quick playground to visualize the problem, hopefully it helps understand what I'm talking about.
In your copying initialiser in BookShelfViewModel you don't actually clone the books array. You need to add self.books = original.books?.clone() to required init(original: BookShelfViewModel)
class BookShelfViewModel: Copying {
var bookShelf: BookShelf
var number: Int
var books: [BookViewModel]?
init(bookShelf: BookShelf) {
self.bookShelf = bookShelf
self.number = bookShelf.number
}
required init(original: BookShelfViewModel) {
self.bookShelf = original.bookShelf
self.books = original.books?.clone()
self.number = original.number
}
}

Instance Member Cannot Be Used On Type - Firebase

I am new to Swift and I am following a tutorial on how to create a social media app with Xcode and Firebase. However, I got this error:
Instance member 'database' cannot be used on type 'DatabaseReference'
Here is my code:
import Foundation
import Firebase
class Post {
private var _username: String!
private var _userImg: String!
private var _postImg: String!
private var _likes: Int!
private var _postKey: String!
private var _postRef: DatabaseReference
var username: String {
return _userImg
}
var postImg: String {
get {
return _postImg
}set {
_postImg = newValue
}
}
var likes: Int {
return _likes
}
var postKey: String {
return _postKey
}
init(imgUrl: String, likes: Int, username: String, userImg: String) {
_likes = likes
_postImg = postImg
_username = username
_userImg = userImg
}
init(postKey: String, postData: Dictionary<String, AnyObject>) {
_postKey = postKey
if let username = postData["username"] as? String {
_username = username
}
if let userImg = postData["userImg"] as? String{
_userImg = userImg
}
if let postImage = postData["imageUrl"] as? String {
_postImg = postImage
}
if let likes = postData["likes"] as? Int {
_likes = likes
}
_postRef = DatabaseReference.database().reference().child("posts")
}
}
I get my error on the third to last line that says:
_postRef = DatabaseReference.database().reference().child("posts")
The database property is an instance type, meaning it must be referenced by an instance of DatabaseReference. Your call to DatabaseReference.database is accessing for a class, or static, type. You need to change your call to an instance of DatabaseReference.
Presumably, you need to initialize an instance of DatabaseReference. I don't know Firebase to know what is required for that, but that will take care of your issue.
Essentially:
let databaseReference = DatabaseReference() // Likely won't work, but some init method here will
_postRef = databaseReference.database()... // Whatever you need here
It sounds like you're looking for either:
_postRef = Database.database().reference("posts")
Or
_postRef = DatabaseReference.root.child("posts")

How to convert datas in Swift from NSArray to Dictionary?

I need convert NSArray to Dictionary, but don't know how can I do it.
After fetch request I have result in NSArray. This my request:
var results: NSArray = []
func fetchUpdateAttendee() {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Attendee")
let predicate = NSPredicate(format: "needUpdate != false")
fetchRequest.predicate = predicate
results = try! DBWorker.context.fetch(fetchRequest) as NSArray
results.forEach { result in
print(result)
}
var results: NSArray = []
print(results) give me
<Attendee: 0x60c000097750> (entity: Attendee; id: 0x60c000422200 <x-coredata:///Attendee/t9E88E2EE-9258-4FAE-AF80-9B036838C6D631> ; data: {
address = "1411 E 31st St";
affiliation = "";
attendeeType = nil;
city = Aguanga;
degree = MD;
email = "";
fax = "";
firstName = Oliver1212;
fullStateLicense = "";
id = nil;
lastName = Aalami;
meeting = nil;
needUpdate = 1;
phone = "";
signature = nil;
signatureTimeStamp = nil;
specialty = Surgery;
state = CA;
stateLicense = "";
status = nil;
timeStamp = nil;
zip = 92536;
})
I need to put these datas to: let dic4Attendee: [String: Any] = [:]
This is a Core Data NSManagedObject subclass, so the code is supposed to be
var results = [Attendee]()
func fetchUpdateAttendee() {
let fetchRequest = NSFetchRequest<Attendee>(entityName: "Attendee")
let predicate = NSPredicate(format: "needUpdate == TRUE")
fetchRequest.predicate = predicate
do {
results = try DBWorker.context.fetch(fetchRequest)
results.forEach { result in
print(result)
}
} catch { print(error) }
}
never use NSArray to represent an array of NSManagedObject subclass.
Add a property dictionaryRepresentation in the Attendee class and return the key value pairs you need for example
var dictionaryRepresentation : [String:Any] {
return ["address" : address,
"affiliation" : affiliation,
"city" : city
// and so on
]
}
then map the array
let mappedArray = results.map{ $0.dictionaryRepresentation }

Cannot assign to the result of this expression with generics

I have the following generic class where I want to manage a string hash:
class NamedProfile<T> {
private var set = [String:T]()
private var profiles = [String]()
private let userDefaults = NSUserDefaults.standardUserDefaults()
private let profileName:String
var currentSet = ""
init(name:String, set:[String:T]) {
profileName = name
self.set = set
if let existingProfiles = userDefaults.objectForKey(name) as? [String] {
profiles = existingProfiles
}
for key in profiles {
if let existingProfile = userDefaults.objectForKey(profileNamed(name)) as? T {
set[key] = existingProfile // <-- error
}
}
}
private func profileNamed(name:String) -> String { return "\(profileName) \(name)" }
}
Why does the compiler croak in the above assignment?
In
init(name:String, set:[String:T]) {
// ...
set[key] = existingProfile // <-- error
// ...
}
set refers to the (immutable) method parameter.
Use self.set instead to refer to the property.

How to list all Variables of a class in swift

Is there a way to list all Variables of a class in Swift?
For example:
class foo {
var a:Int? = 1
var b:String? = "John"
}
I want to list it like this: [a:1, b:"John"]
How you can do it in Swift 3.0 recursively:
import Foundation
class FirstClass {
var name = ""
var last_name = ""
var age = 0
var other = "abc"
func listPropertiesWithValues(reflect: Mirror? = nil) {
let mirror = reflect ?? Mirror(reflecting: self)
if mirror.superclassMirror != nil {
self.listPropertiesWithValues(reflect: mirror.superclassMirror)
}
for (index, attr) in mirror.children.enumerated() {
if let property_name = attr.label {
//You can represent the results however you want here!!!
print("\(mirror.description) \(index): \(property_name) = \(attr.value)")
}
}
}
}
class SecondClass: FirstClass {
var yetAnother = "YetAnother"
}
var second = SecondClass()
second.name = "Name"
second.last_name = "Last Name"
second.age = 20
second.listPropertiesWithValues()
results:
Mirror for FirstClass 0: name = Name
Mirror for FirstClass 1: last_name = Last Name
Mirror for FirstClass 2: age = 20
Mirror for FirstClass 3: other = abc
Mirror for SecondClass 0: yetAnother = YetAnother
The following should use reflection to generate the list of members and values. See fiddle at http://swiftstub.com/836291913/
class foo {
var a:Int? = 1
var b:String? = "John"
}
let obj = foo()
let reflected = reflect(obj)
var members = [String: String]()
for index in 0..<reflected.count {
members[reflected[index].0] = reflected[index].1.summary
}
println(members)
Output:
[b: John, a: 1]
Maybe a bit late for the party, but this solution using reflection and Mirror is 100% working:
class YourClass : NSObject {
var title:String
var url:String
...something other...
func properties() -> [[String: Any]] {
let mirror = Mirror(reflecting: self)
var retValue = [[String:Any]]()
for (_, attr) in mirror.children.enumerated() {
if let property_name = attr.label as String! {
retValue.append([property_name:attr.value])
}
}
return retValue
}
}
and somewhere in your code...
var example = MoreRow(json: ["title":"aTitle","url":"anURL"])
print(example.listPropertiesWithValues())
I got clue from here. https://medium.com/#YogevSitton/use-auto-describing-objects-with-customstringconvertible-49528b55f446
This is a demo above Swift 4.0.
import Foundation
extension CustomStringConvertible {
var description : String {
var description: String = ""
if self is AnyObject { // unsafeAddressOf((self as! AnyObject))
description = "***** \(type(of: self)) - <\(Unmanaged.passUnretained(self as AnyObject).toOpaque())>***** \n"
} else {
description = "***** \(type(of: self)) *****\n"
}
let selfMirror = Mirror(reflecting: self)
for child in selfMirror.children {
if let propertyName = child.label {
description += "\(propertyName): \(child.value)\n"
}
}
return description
}
}
extension NSObject {
var description: String {
var description: String = ""
if self is AnyObject { // unsafeAddressOf((self as! AnyObject))
description = "***** \(type(of: self)) - <\(Unmanaged.passUnretained(self as AnyObject).toOpaque())>***** \n"
} else {
description = "***** \(type(of: self)) *****\n"
}
let selfMirror = Mirror(reflecting: self)
for child in selfMirror.children {
if let propertyName = child.label {
description += "\(propertyName): \(child.value)\n"
}
}
return description
}
}
class AA: CustomStringConvertible {
var a: String = "aaa"
}
class BB: NSObject {
var b: String = "bbb"
}
let aa = AA()
print(aa)
let bb = BB()
print(bb.description)
Output --
***** AA - <0x00000001001038e0>*****
a: aaa
***** BB - <0x0000000100103310>*****
b: bbb