Swift 4 Realm Swift object - swift

I'm trying to use realmSwift in my application in Swift 4 but i have an error.
public class Test : Object {
#objc dynamic var id: Int = 0
#objc dynamic var long: Double? = 0
convenience init(id: Int, long:Double?) {
self.init()
self.id = id
self.long = long
}
override public class func primaryKey() -> String {
return "id"
}
}
Error for line with long variable.
Property cannot be marked #objc because its type cannot be represented in Objective-C
Thx for help

As the docs clearly state, numeric types cannot simply be marked Optional, because Optional numeric types cannot be represented in Objective-C. You need to use RealmOptional to store Optional numeric types in Realm classes.
public class Test : Object {
#objc dynamic var id: Int = 0
let long = RealmOptional<Double>()
}

You have provided Int value to the double, so it's throw error. Use following code for double;
#objc dynamic var value: Double = 0.0
I hope this will fix your issue.
For more info: https://realm.io/docs/swift/latest#property-attributes

Related

Swift Error: 'Human' cannot be constructed because it has no accessible initializers

I am trying to instantiate an object from a class in swift. When I instantiate I am getting this error:
'Human'cannot be constructed because it has no accessible initializers
My Codes:
class Human{
var firstName: String
var lastName : String
var age : Int
var spouseName: String?
var childName : String?
var currentSpeed: Double = 0
func walk(speedIncrease: Double){
currentSpeed += speedIncrease*2
}
func brake(){
self.currentSpeed = 0
}
}
let tanvir = Human(firstName: "tanvir", lastName:"Alam", age: 32, currentSpeed:30)
print("gmk")
What am I doing wrong? Please Explain. Thank You.
Unlike structs where the initializer is synthesized classes require an explicit init method.
Add
init(firstName : String, lastName: String, age: Int, currentSpeed: Double = 0.0 {
self.firstName = firstName
self.lastName = lastName
self.age = age
self.currentSpeed = currentSpeed
}
and remove the default value of currentSpeed
A much simpler solution is to replace class with struct.

How to assign a value to optional property of class

I've tried a bunch of different ways to assign a value to stepperValue to no avail. I get my Offence model filled through Firebase and I simply want to "assign" a stepper value to each offences so that I can make calculations i.e points X stepperValue .
Model swift file:
class Offence : Comparable {
var section: String
var name: String
var cost: Int
var points: Int
var stepperValue: Double?
init(section: String, name: String, cost: Int, points: Int) {
self.section = section
self.name = name
self.cost = cost
self.points = points
}
class Variables {
static var selectedOffencesArray: [Offence] = [Offence]()
}
This one is in its own TableViewCell class in its own swift file
#IBAction func stepperValueChanged(_ sender: Any) {
for offence in Variables.selectedOffencesArray {
offence.stepperValue! = 3.0
}
The following just work
for offence in Variables.selectedOffencesArray {
offence.stepperValue = 3.0 // << no force (!) needed
}

Cannot create class object or array of class objects

I'm working on a project thatand am simply trying to create a object instance of a simple custom class:
import Foundation
class Set {
private var gam1: Int!
private var gam2: Int!
init (gam1: Int, gam2: Int) {
self.gam1 = gam1
self.gam2 = gam2
}
//returns set info as array
func getStats () -> [Int] {
let arr = [gam1!, gam2!]
return arr
}
}
The class simply stores a few variables for use later and I want an array of such objects to store several values. However, when I try to create a n instance of the class in a different class I get errors:
import Foundation
class AnotherClass {
var mySet = Set(gam1: 6, gam2: 5) //error 1
//array of set objects
var setArray = [Set]() // error 2
//returns array of set objects
func getSets () -> [Set] { //error 3
return setArray
}
}
The errors state:
Cannot find an initializer for type 'Set' that accepts an argument list of type '(gam1: Int, gam2: Int)'
Cannot invoke initializer for type '[Set]' with no arguments
and
Reference to generic type 'Set' requires arguments in <...>
Any ideas of what the issue is here? could the 'Set' name of the class be conflicting with a reserved keyword?
Many thanks,
Kw
The issue that you are having is due to the naming conflict between Set in the Swift standard library and the one you defined.
This is never a good idea. Instead, give it a more descriptive name (and one that doesn't conflict with anything else). For instance, call it gamHolder and initialize it gamHolder(gam1: <an int>, gam2: <another int>).
Also, if you have defined variables inside the init function they do not need to be forced unwrapped optionals.
For example:
class myClass {
var myInt: Int
init(anInt: Int) {
myInt = anInt
}
}
You defined 2 parameters in your init method (since gam1 and gam2 are not optional). So, you have 2 solutions:
1 - You add parameters into your init call (like this):
var mySet = Set(gam1: 1, gam2: 2)
2 - You change gam1 and gam2 to optionals and you add a zero parameters init:
class Set {
private var gam1: Int?
private var gam2: Int?
init() {
}
init(gam1: Int, gam2: Int) {
self.gam1 = gam1
self.gam2 = gam2
}
// returns set info as array
func getStats() -> [Int] {
let arr = [gam1!, gam2!]
return arr
}
}
So, you will be able to call it like this: var mySet = Set()
Also: be careful: Set is a class used in the Swift standard library. It's never a good idea to use same class names than Swift Standard Library. A name like TenisSet would be better.
Edit:
Here is a final working example with a renamed class:
class TenisSet {
private var gam1: Int?
private var gam2: Int?
init() {
}
init(gam1: Int, gam2: Int) {
self.gam1 = gam1
self.gam2 = gam2
}
// returns set info as array
func getStats() -> [Int] {
let arr = [gam1!, gam2!]
return arr
}
}
class AnotherClass {
var mySet = TenisSet()
// array of set objects
var setArray = [TenisSet]()
// returns array of set objects
func getSets() -> [TenisSet] {
return setArray
}
}

Maintain value semantics in Swift struct, which contains object reference

I have a Swift struct which contains an object for internal storage. How can I make sure the struct has value semantics?
public struct Times {
private let times = NSMutableIndexSet()
mutating func addTimeRange(openTime: Int, closeTime: Int) {
self.times.addIndexesInRange(NSRange(location: openTime, length: closeTime - openTime))
}
}
Swift 3 Update
Swift 3 includes value types for many types from the Foundation framework. There is now an IndexSet struct, which bridges to NSIndexSet. The internal implementation is similar to the Swift 2 solution below.
For more information on the new Foundation value types see: https://github.com/apple/swift-evolution/blob/master/proposals/0069-swift-mutability-for-foundation.md
Old approach in Swift 2
The copy-on-write approach is the right solution. However, it is not necessary to create a copy of the NSMutableIndexSet, if only one struct instance references it. Swift provides a global function called isUniquelyReferencedNonObjC() to determine if a pure Swift object is only referenced once.
Since we cannot use this function with Objective-C classes, we need to wrap NSMutableIndexSet in a Swift class.
public struct Times {
private final class MutableIndexSetWrapper {
private let mutableIndexSet: NSMutableIndexSet
init(indexSet: NSMutableIndexSet) {
self.mutableIndexSet = indexSet
}
init() {
self.mutableIndexSet = NSMutableIndexSet()
}
}
private let times = MutableIndexSetWrapper()
mutating func addTimeRange(openTime: Int, closeTime: Int) {
// Make sure our index set is only referenced by this struct instance
if !isUniquelyReferencedNonObjC(&self.times) {
self.times = MutableIndexSetWrapper(indexSet: NSMutableIndexSet(indexSet: self.times.mutableIndexSet))
}
let range = NSRange(location: openTime, length: closeTime - openTime)
self.times.mutableIndexSet.addIndexesInRange(range)
}
}
Store an NSIndexSet instead of an NSMutableIndexSet. That is exactly why the immutable superclass exists.
public struct Times {
private var times = NSIndexSet()
mutating func addTimeRange(openTime: Int, closeTime: Int) {
let t = NSMutableIndexSet(indexSet:self.times)
t.addIndexesInRange(NSRange(location: openTime, length: closeTime - openTime))
self.times = NSIndexSet(indexSet:t)
}
}
If this were a class instead of a struct, you could cause the last step to be performed automatically by declaring times as #NSCopying and then just using simple assignment:
public class Times {
#NSCopying private var times = NSIndexSet()
func addTimeRange(openTime: Int, closeTime: Int) {
let t = NSMutableIndexSet(indexSet:self.times)
t.addIndexesInRange(NSRange(location: openTime, length: closeTime - openTime))
self.times = t // ensure immutable copy
}
}
It might be an option to use Swift's native Set type which has value-semantics built in since it is a struct itself.
public struct Times {
private var times = Set<Int>()
mutating func addTimeRange(openTime: Int, closeTime: Int) {
(openTime ..< closeTime).map({ index -> Void in self.times.insert(index) })
}
}
let t1 = Times()
var t2 = t1
t2.addTimeRange(0, closeTime: 3)
println(t1.times) // []
println(t2.times) // [2, 0, 1]

Swift: Realm error at init "NULL is not supported as an RLMObject property". But I don't have a NULL

It seems most people with this error are trying to create null strings. I just have three properties
dynamic var babyEvent: Int
dynamic var eventDate: NSDate
dynamic var timeSpent: Int
which are initialized in init() to
override init()
{
self.babyEvent = BabyWet
self.eventDate = NSDate()
self.timeSpent = 5
super.init()
}
but by the time super.init() is called I get
'(null)' is not supported as an RLMObject property.
There are two Ints and one NSDate, all of which are valid Realm property types. So why am I getting this error?
Realm doesn't support Swift enum's with no raw value. But adding a raw type to the BabyEvent enum and assigning the raw value to your realm objects works:
enum BabyEvent: Int {
case BabyWet, case BabyDry
}
class MyRealmObject: RLMObject {
dynamic var babyEvent = BabyEvent.BabyWet.rawValue
dynamic var eventDate = NSDate()
dynamic var timeSpent = 0
}
In Swift Enums have a specific type. So while you think you are passing an Int for BabyWet you are actually passing something of that specific type.
It seems that you have an Enum for the BabyEvent, so you should really have a look at the rawValue property:
self.babyEvent = BabyWet.rawValue
As I wrote, you can just set the starting values in the model definitions:
class TestClass: RLMObject {
dynamic var babyEvent: Int = 1
dynamic var eventDate: NSDate = NSDate()
dynamic var timeSpent: Int = 5
}
but this also works for me:
class TestClass: RLMObject {
dynamic var babyEvent: Int
dynamic var eventDate: NSDate
dynamic var timeSpent: Int
override init() {
babyEvent = 1
eventDate = NSDate()
timeSpent = 5
super.init()
}
}
In both cases I simply use
let realm = RLMRealm.defaultRealm()
var myTestObject = TestClass()
realm.beginWriteTransaction()
realm.addObject(myTestObject)
realm.commitWriteTransaction()
to create and add the object to the Realm.