2014-10-08 2 views
32

У меня есть уникальный ресурс для каждого объекта ChatData.Как установить ключ автоматического увеличения в Realm?

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

Но каждый раз, когда я создаю новый объект, я должен запросить все объекты и получить последнее.

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

Есть ли эффективный способ заменить эту реализацию?

ответ

50

Царство не имеет автоматического прироста, поэтому вам нужно будет управлять этим самостоятельно. Вопрос, который я хотел бы предложить вам рассказать о ваших данных:

Нужно ли иметь последовательные, непрерывные, целочисленные идентификаторы?

Если нет, то может быть достаточно первичного ключа с уникальной строкой. Затем вы можете использовать что-то вроде [[NSUUID UUID] UUIDString] для генерации уникальных идентификаторов строк. Самое приятное в том, что эти UUID более или менее гарантированно уникальны даже в многопоточных сценариях.

Если это так, возможно, было бы более эффективно всегда хранить последний номер в памяти, чтобы запросы не требовались каждый раз при создании нового идентификатора. Если объекты могут быть созданы в нескольких потоках, убедитесь, что ваша функция nextPrimaryKey() потокобезопасна, в противном случае она может генерировать одинаковый номер дважды (или больше!).

+3

Есть ли планы по добавлению поведения автоинкремента в Realm? –

+1

Да, эта функциональность подходит, но у меня нет временной шкалы для вас. – jpsim

+2

Это нормально помещать это в словарь '+ defaultPropertyValues', не так ли? Я имею в виду '[[NSUUID UUID] UUIDString]'. – Darrell

8

Autoincrement идентификатор Realm в Swift 2.0: вставки кода в классе области и использования записи объекта

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 
    } 
} 

в использовании записи файла:

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]) 
    }) 
+5

Это и дорого, и не потокобезопасно. – jpsim

+1

Спасибо спасибо :) Nice and Quick! – Abo3atef

+0

Да, возможно, некоторые проблемы возникают при многопоточности записи и чтения. которым могут потребоваться некоторые дополнительные процессы. –

7

вы будете использовать этот код для автоматического инкрементного первичного ключа in Swift:

var myvalue = realm.objects(ChatData).map{$0.id}.maxElement() ?? 0 
myvalue = myvalue + 1 
+0

Спасибо за отличное решение ... –

+0

Приложение завершено с этой ошибкой «Первичный ключ нельзя изменить после того, как объект вставлен». Любой альтернативный способ обновления Первичного ключа? –

+1

Отличное решение. Работает как шарм. Спасибо :) – Hrishikesh

0

Я использовал createDate в моей модели, поэтому я создал Unix timeStamp на основе этой даты и использовал его как primaryKey моего объекта.

Это 99,99% гарантированно будет уникальным в моем случае (потому что метка времени точна для второго), но это может зависеть от вашего варианта использования. Он менее надежный, чем UUID, но во многих случаях этого достаточно.

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 
    } 
} 
0

Это, по существу, то, что предлагается в ответ jpsim, используя UUID для генерации уникальных ключей. Мы запрашиваем перед вставкой, чтобы обеспечить уникальность. Это чаще всего будет выполнять только один запрос; в очень редком случае столкновения он будет продолжаться до тех пор, пока не найдет уникальный идентификатор. Это решение является естественным расширением для типа Realm и является общим по классам, которое наследуется от Object. Класс должен реализовать primaryKey и вернуть имя объекта String.

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) 
    } 
} 
0

В Realm вам необходимо управлять идентификатором автоинкремента, поэтому есть много способов управлять им. Ниже приведены некоторые из них.

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

вызов этого метода каждый раз при добавлении записи.

+0

Я получил эту ошибку " Первичный ключ не может быть изменен после того, как объект вставлен "@Tofaani Kaanudo –

Смежные вопросы