Initializing Realm Object class with multiple required initilizers - swift

I am initializing Realm object and I am getting these errors when I try to initialize the class:
After I add the initializer for realm, the errors are still there. Is this a bug with xcode?
Looking at the sample code for swift-realm ios project here, it looks like I don't need to call the required realm. Maybe the sample code is outdated.
EDIT ---
Here's a paste of the code:
class AgencyR: Object {
#objc dynamic var agency_id: String = ""
#objc dynamic var agency_name: String = ""
#objc dynamic var agency_timezone: String = ""
#objc dynamic var agency_url: String = ""
#objc dynamic var agency_lang: String = ""
#objc dynamic var agency_phone: String = ""
#objc dynamic var agency_fare_url: String = ""
required init(realm:Realm, agency_id: String, agency_name: String, agency_timezone: String, agency_url: String, agency_lang: String, agency_phone: String, agency_fare_url: String) {
self.init()
self.agency_id = agency_id
self.agency_name = agency_name
self.agency_timezone = agency_timezone
self.agency_url = agency_url
self.agency_lang = agency_lang
self.agency_phone = agency_phone
self.agency_fare_url = agency_fare_url
}
override static func primaryKey() -> String? {
return self.agency_id
}
}

If you wanted to create a designated initializer for an Object subclass, you'd need to implement all required initializers of Object since the compiler will not be able to synthetise those for you anymore.
You can get around this issue by making your custom initializer a convenience initializer rather than a designated one, which will allow you to call a designated initializer of the class rather than having to call the superclass initializer. You can still mark the convenience initializer as required.
You also have an issue in your primaryKey function. Since the function is a type function, you don't have access to the instance from inside the function, so you cannot call self to access an instance property. However, there's no need to do that anyways, since you simply need to return the variable name as a String that you want to use as a primary key.
class A: Object {
#objc dynamic var a = 1
required convenience init(_ a:Int) {
self.init()
self.a = a
}
override static func primaryKey()->String?{
return "a"
}
}

It should be -> Object, instead of ->String? as agency_id is of type Object.Try this.

Related

Understanding struct initialiser if it contain private property

I want to understand how initialiser work if struct contains private properties. I have following code:
struct Doctor {
var name: String
var location: String
private var currentPatient = "No one"
}
let drJones = Doctor(name: "Esther Jones", location: "Bristol")
This throws an error:
Cannot invoke initializer for type 'Doctor' with an argument list of
type '(name: String, location: String)'
My Assumption is: Default Memeberwise initialiser contains private property which can't be called from outside.
But I am confused by following code:
struct Doctor {
private var currentPatient = "No one"
}
let drJones = Doctor()
How this is working?, it is not throwing any error.
You can't use default memberwise initialiser for assigning struct's property with private access level modifier.
Your second example works, because you gave your property default value so there is no need to assign it while you're initalizing it.
If you need to assign your private property using initializer, you have to write your own
init(name: String, location: String, currentPatient: String) {
self.name = name
self.location = location
self.currentPatient = currentPatient
}

Making Realm & Unbox play nice

I am learning to parse JSON in Swift, coming from Android/Java, and I am using Unbox by John Sundell to help me with this, which reminds me of GSON.
Reference: Unbox pod
I use Realm as a database to store data locally.
Reference: Realm.io
It would be great to find a workflow to parse a class with JSON and save it to Realm. I don't want to have a struct that implements Unboxable AND a class that implements Object (Realm), because then I have to reflect the two. That isn't too much work for my current project, but it is kinda ugly...
Did any of you try a similar workflow?
I don't think you need two separate types. My suggestion is to create your objects as Swift classes that inherit from Realm's Object class, and then also conform them to the Unboxable protocol that Unbox offers. (Although the examples on Unbox's page use struct models, there's nothing in the code or documentation that indicates that classes wouldn't work.)
Realm model objects work just like any other classes: in addition to defining whatever properties on the objects you'd like stored in the database, you can also define methods and initializers, and even specify properties that you want Realm to ignore. This allows you to create an object that both serves as a Realm model and also a JSON model compatible with Unbox.
A more concise approach that doesn't require to override required initialisers (based on a tweet by Marin Todorov):
class Car: Object, Unboxable {
dynamic var vendor: String = ""
dynamic var modelName: String = ""
dynamic var electric: Bool = false
required convenience init(unboxer: Unboxer) throws {
self.init()
self.vendor = try unboxer.unbox(key: "vendor")
self.modelName = try unboxer.unbox(key: "modelName")
self.electric = try unboxer.unbox(key: "electric")
}
}
Here is an example that works perfectly for me:
class ProviderRealm: Object, Unboxable {
dynamic var identifier: String = "demo"
dynamic var name: String?
dynamic var logo: String?
/// Initializer used for unboxing of JSON string
required init(unboxer: Unboxer) throws {
self.identifier = (try? unboxer.unbox(key: "identifier")) ?? "demo"
self.name = try? unboxer.unbox(key: "name")
self.logo = try? unboxer.unbox(key: "logo")
super.init()
}
required init(realm: RLMRealm, schema: RLMObjectSchema) {
super.init(realm: realm, schema: schema)
}
required init() {
super.init()
}
required init(value: Any, schema: RLMSchema) {
super.init(value: value, schema: schema)
}
override static func primaryKey() -> String? {
return "identifier"
}
}

how to create a singleton in swift with init variables

I am trying to create a singleton class in swift but I am getting an error
"cannot create a single-element tuple with an element label"
i am not getting it.
class GroupObject {
// we want the group object to be a singleton
var name: String
var id: Int
var groupJsonObject: JSON
init(groupJsonObject: JSON){
self.groupJsonObject = groupJsonObject
self.id = groupJsonObject["id"].int!
self.name = groupJsonObject["name"].string!
}
class var sharedInstance : GroupObject {
struct Static {
static let instance : GroupObject = GroupObject(groupJsonObject: JSON) // this is the problem line.
}
return Static.instance
}
}
The problem is that you cannot pass a parameter to the singleton. Your singleton implementation doesn't know to what JSON refers.
If you want this to be a singleton, you'd have to initialize the groupJsonObject separately from the initialization of the shared instance. For example:
class GroupObject {
var name: String!
var id: Int!
var groupJsonObject: JSON! {
didSet {
id = groupJsonObject["id"].int!
name = groupJsonObject["name"].string!
}
}
static let sharedInstance = GroupObject() // btw, this is a more concise syntax for declaring a singleton
}
And then, when you want to initialize those properties, you could do:
GroupObject.sharedInstance.groupJsonObject = json
If your "singleton" is supposed to hold some data passed to it on instantiation, how will it get that data? Where/when is it available?
I think you don't actually want a singleton at all; you want an instance created with your JSON data to be accessible from different points in your application. In that case, pick some "master controller", create it there, then pass it along to other controllers as needed.

Why do I have to override my init in Swift now?

import Foundation
class Student: NSObject
{
var name: String
var year: Int
var major: String
var gpa : String
init(name:String, year:Int, major:String, gpa:String)
{
self.name = name
self.year = year
self.major = major
self.gpa = gpa
}
convenience init()
{
//calls longer init method written above
}
}
--
The error shows itself atthe line of the convenience init
Overriding declaration requires an 'override' keyword
I've tried Googling this and reading guides on initializers in Swift, but it seems like they were able to make their initializers just fine without overriding anything.
init is a designated initializer for NSObject. If you override it, you must mark this as override and call a superclass designated initializer. This follows the normal rules for initializer inheritance.
it looks like your convenience initializer is empty which is why you get the error. For example if you change it to:
convenience init() {
self.init(name: "", year: 0, major: "nothing", gpa: "4.0")
}
the error would go away.
I wonder why you set up Student to inherit from NSObject. It doesn't look necessary for your class.

Swift: How to add a class method in 'String" extension

I want to add a class function into extension:
extension String {
class func test () {
}
}
I get the error: Class methods are only allowed within classes; use 'static' to declare a static method
Or how should i call " String.test()"
But for NSString
extension NSString {
class func aaa () {
}
}
no errors.
If i add static keyword:
extension String {
static func aaa () {
self.stringByAppendingString("Hello")
}
}
Got: Expression resolves to an unused function,
So how should i add a class function also want to use self. method.
EDIT: This works!
extension String {
static func aaa (path:String) -> String {
return path.stringByAppendingString("Hello")
}
}
but about #lan's answer:
mutating func bbb(path: String) {
self += "world"
}
When i type it appears like this:
String.bbb(&<#String#>)
String.bbb(&"nihao")
Cannot invoke 'bbb' with an argument list of type '(String)'
Class and static functions are not called on an instance of a class/struct, but on the class/struct itself, so you can't just append a string to a class.
Apple Documentation:
Within the body of a type method, the implicit self property refers to
the type itself, rather than an instance of that type.
You can, however, append a string to a variable instance of a String using the mutating keyword:
extension String {
mutating func aaa() {
self += "hello"
}
}
let foo = "a"
foo.aaa() // ERROR: Immutable value of type 'String' only has mutating members named 'aaa'
var bar = "b"
bar.aaa() // "bhello"
If you are trying to use a pointer to a string as a parameter, you can use the inout keyword to alter the inputed string:
extension String {
static func aaa(inout path: String) {
path += "Hello"
}
}
var foo = "someText"
String.aaa(&foo)
foo //someTextHello
While correct, it's somewhat atypical to see a mutating member added to a String extension as shown in Ian's answer. Strings (and value types in general) are meant to be immutable so the only way to use a mutating method is to declare instances var at the call site. Most of the time in your code you should be using let constants.
As such, it is much more common to extend structs to return new instances. So this is typical:
extension String {
func appending(_ string: String) -> String {
return self + string
}
}
and then at the call site:
let hello = "Hello, "
let helloWorld = hello.appending("World!")
You'll note of course that I'm not using static at all. That's because appending(_:) needs to use the current instance value of the String we're appending to, and class/static do not refer to instances and therefore do not have values.
"Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type."
Thus when you extend a type by adding a type method you can only call other type methods through self. If you want to call an instance method you need to create an instance and call a method on that.