39

I have a unique msgid for each ChatData object.

@interface ChatData : RLMObject
@property NSInteger msgid;
....
@end

But each time I create a new object I have to query all objects and get the last msgid.

RLMArray *all = [[ChatData allObjects] arraySortedByProperty:@"msgid" ascending:YES];
ChatData *last = [all lastObject];
ChatData *newData = [[ChataData alloc]init];
newData.msgid = last.msgid+1;

Is there an efficient way to replace this implementation?

drinking
  • 1,533
  • 3
  • 15
  • 22

6 Answers6

58

Realm doesn't have auto increment behavior, so you'll need to manage that yourself. A question I'd encourage you to ask yourself about your data:

Is it necessary to have sequential, contiguous, integer ID's?

If not, then a unique string primary key might be sufficient. Then you can use something like [[NSUUID UUID] UUIDString] to generate unique string ID's. The nice thing about this is that these UUID's are more or less guaranteed to be unique, even in multithreaded scenarios.

If so, it might be more efficient to always keep the last number in memory, so that queries aren't required every time a new ID should be generated. If objects might be created in multiple threads, make sure to make your nextPrimaryKey() function thread-safe, otherwise it might generate the same number twice (or more!).

jpsim
  • 14,329
  • 6
  • 51
  • 68
  • 4
    Are there any plans to add autoincrement behavior to Realm? – Kurt Mueller Nov 04 '14 at 17:51
  • 1
    Yes, that functionality is coming, but I don't have a timeline for you. – jpsim Nov 05 '14 at 17:04
  • 2
    It is okay to put this in the `+defaultPropertyValues` dictionary isn't it? I'm referring to `[[NSUUID UUID] UUIDString]`. – Darrell Jan 16 '15 at 01:46
  • @jpsim what about performance when using strings instead of integers as identifiers? Should I care about it? – Tomasz Wójcik Sep 24 '15 at 16:39
  • as with all things performance-related, profile and then optimize if you identify it's a bottleneck. Random integer generation may work well for small datasets as well, but with higher risk of collisions. – jpsim Sep 25 '15 at 19:52
  • @jpsim I have same question as darrel. Is it ok to put [[NSUUID UUID] UUIDString] in defaultPropertyValues? – sanjana Oct 12 '15 at 13:49
  • 5
    For *Swift* use this `NSUUID().UUIDString` – Mohammad Zaid Pathan Dec 25 '15 at 20:56
  • 1
    checkout https://github.com/realm/realm-cocoa/issues/2591#issuecomment-170259579 if anyone cares Realm autoincrement feature – Puttin Jan 16 '16 at 02:34
  • Per the issue in the previews comment, Realm has officially said that they don't plan on adding auto increment because it would interfere with adding multi-process support. – Jade Mar 25 '16 at 19:42
  • "more or less guaranteed". Is it guaranteed or no? Not sure that can be qualified. – Patrick Goley Dec 20 '16 at 04:33
  • one in 2^36 chance of collision is "more or less" guaranteed to be unique: http://stackoverflow.com/a/35286235/373262 – jpsim Dec 20 '16 at 07:19
16

You are use this Code for Auto Incremental Primary Key in Swift :

var myvalue = realm.objects(ChatData).map{$0.id}.maxElement() ?? 0
myvalue = myvalue + 1
Kirit Modi
  • 23,155
  • 15
  • 89
  • 112
11

Autoincrement id Realm in Swift 2.0: insert code in class realm and object write use

import Foundation
import RealmSwift

class Roteiro: Object {

dynamic var id = 0
dynamic var Titulo = ""
dynamic var Observacao = ""
dynamic var status = false
dynamic var cadastrado_dt = NSDate()

override static func primaryKey() -> String? {
    return "id"
}

//Incrementa ID
func IncrementaID() -> Int{
    let realm = try! Realm()
    if let retNext = realm.objects(Roteiro.self).sorted(byKeyPath: "id").first?.id {
        return retNext + 1
    }else{
        return 1
    }
}

in file write use:

let Roteiro_Add = Roteiro()
    //increment auto id
    Roteiro_Add.id = Roteiro_Add.IncrementaID()

    Roteiro_Add.Titulo = TituloDest
    Roteiro_Add.Observacao = Observacao
    Roteiro_Add.status = false


    let realm = try! Realm()
    try! realm.write({ () -> Void in
        realm.add([Roteiro_Add])
    })
Pablo Ruan
  • 1,681
  • 1
  • 17
  • 12
  • 2
    Thanks bro :) Nice and Quick! – Atef Jun 15 '16 at 13:15
  • Yeah, it might exists some issues on multi-thread write and read. which may need some additional processes. – Ryan Chou Aug 18 '16 at 00:54
  • 2
    if let retNext = realm.objects(Roteiro.self).sorted(byKeyPath: "id").first?.id { this should be last item like if let retNext = realm.objects(Ordernew.self).sorted(byKeyPath: "id").last?.id { – Ammar Mujeeb Apr 10 '19 at 11:46
5

In Realm you need to manage auto-inc ID it self so there are many ways to manage it. Below is some of them.

 func incrementID() -> Int {
        let realm = try! Realm()
        return (realm.objects(Person.self).max(ofProperty: "id") as Int? ?? 0) + 1
    }

call this method every time when you adding record.

Govaadiyo
  • 5,644
  • 9
  • 43
  • 72
1

I used a creationDate in my Model, so I created a Unix timeStamp based on this date, and used it as the primaryKey of my object.

It's 99.99% guaranteed to be unique in my case (because the timestamp is precise to the second), but it may depend on your use case. It's less robust than a UUID, but in many cases it's sufficient.

extension NSDate {

    /** Returns a NSDate instance from a time stamp */
    convenience init(timeStamp: Double) {
        self.init(timeIntervalSince1970: timeStamp)
    }
}


extension Double {

    /** Returns a timeStamp from a NSDate instance */
    static func timeStampFromDate(date: NSDate) -> Double {    
        return date.timeIntervalSince1970
    }
}
Frederic Adda
  • 5,905
  • 4
  • 56
  • 71
0

This is essentially what is suggested in jpsim's answer, using UUID to generate unique keys. We query prior to inserting to ensure uniqueness. This will most often only incur one query; in the very rare case of a collision it will continue until it finds a unique id. This solution is a natural extension on the Realm type and is generic over classes that inherits from Object. The class must implement primaryKey and return the name of a String property.

extension Realm {

    func createAutoUnique<T: Object>(_ type: T.Type) -> T {

        guard let primaryKey = T.primaryKey() else {

            fatalError("createAutoUnique requires that \(T.self) implements primaryKey()")
        }

        var id: String

        var existing: T? = nil

        repeat {

            id = UUID().uuidString

            existing = object(ofType: type, forPrimaryKey: id)

        } while (existing != nil)

        let value = [
            primaryKey: id
        ]

        return create(type, value: value, update: false)
    }
}
Patrick Goley
  • 5,397
  • 22
  • 42