Realm Korea의 개발자 김용욱 lk@realm.io님이 Realm Seoul 11월 정기 모임에서 Realm의 최신 버전을 소개합니다. 최근 적용된 Java 0.82~0.85 버전과 Objective-C 0.96, Swift 0.96버전까지 Realm version 별 변경 사항을 확인할 수 있습니다.
Realm의 최신 버전과 새로운 기능
김용욱 님의 11월 20일 Realm Seoul 사용자 모임 발표입니다.
빠르게 발전하고 있는 Realm의 최신 버전별 변경 사항과 사용 예, 마이그레이션 방법까지 버전업에 따른 관련 설명을 담고 있습니다. Realm의 최신 버전에서 어떤 기능들을 제공하고 있고 어떻게 적용할 수 있는지 알아 보세요.
Cocoa v.s. Java
- Cocoa 버전의 기능 업데이트가 더 빠름
- 이번 발표에서 다룰 버전
- Cocoa 0.95.1, 0.96
- Java 0.82, 0.83, 0.84, 0.85
Java 0.82
- Primary key에 Index를 적용
- 이전 버전까지는 Primary Key를 적용해도 Index를 설정해야 했음
- 이전 버전에서 마이그레이션할 경우 addSearchIndex 메서드로 index field를 추가해줘야 함
Java 0.83
- 기본형 래퍼 클래스 (Null 가능)
class Person extends RealmObject {
String name;
int age;
Integer Weight; // weight is not required!
}
Person john = realm.createObject(Person.class);
john.setName("John");
john.setAge(25);
john.setWeight(73);
Person bill = realm.createObject(Person.class);
bill.setName("Bill");
bill.setAge(41);
bill.setWeight(null);
- Null이 필요없는 필드에 @Required로 정의 (String, Date, Byte[]가 기본으로 null)
- Null을 쓸 수 있도록 마이그레이션 단계에서 기존 필드를 수정
RealmMigration migration = new RealmMigration() {
@Override
public long execute(Realm realm, long version) {
Table table = realm.getTable(Dog.class);
table.convertColumnToNullable(table.getColumnIndex("name"));
return 1;
}
};
RealmConfiguration realmConfig = new RealmConfiguration.Builder(getContext())
.schemaVersion(1)
.schema(Dog.class)
.migration(migration)
.build();
- 문서를 확인해서 버전별 변화에 따라 마이그레이션하는 것을 추천함
Java 0.84
- 비동기 질의
- 여태까지는 여러 스레드에서 Realm을 자동으로 사용하도록 지원하지 않았음
- 이제 백그라운드에서 질의를 하고 포그라운드에서 결과를 받는 등 다른 스레드에서 사용할 수 있음
RealmResults<User> result = realm.where(User.class)
.equalTo("name", "John")
.or()
.equalTo("name", "Peter")
.findAllAsync();
private RealmChangeListener callback = new RealmChangeListener() {
@Override
public void onChange() { // called once the query complete and on every update
// use the result
}
};
public void onStart() {
RealmResults<User> result = realm.where(User.class).findAllAsync();
result.addChangeListener(callback);
}
- 해제와 상태 확인 가능
public void onStop () {
result.removeChangeListener(callback); // remove a particular listener
// or
result.removeChangeListeners(); // remove all registered listeners
}
result.isLoaded()
- 비동기 트랜잭션 가능: 작업은 백그라운드에서, 결과만 포그라운드에서 받음
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm bgRealm) {
User user = bgRealm.createObject(User.class);
user.setName("John");
user.setEmail("john@corporation.com");
}
}, new Realm.Transaction.Callback() {
@Override
public void onSuccess() {
}
@Override
public void onError(Exception e) {
// transaction is automatically rolled-back, do any cleanup here
}
});
- 비동기 트랜잭션 취소 기능 지원
public void onStop () {
if (transaction != null && !transaction.isCancelled()) {
transaction.cancel();
}
}
- 질의한 결과가 null인지 비었는지 확인하는 유틸리티 함수 추가
// Find all users with no dogs
RealmResults<User> users = realm.where(User.class).isEmpty("dogs").findAll();
// Find all users with at least 1 dog
RealmResults<User> users = realm.where(User.class).not().isEmpty("dogs").findAll();
- 유니크한 결과만 확인하고 싶을 때는 distinct 메서드 사용 (@PrimaryKey와 @index로 지정된 데이터만 사용 가능)
// Returns the set of users that all have a different name
RealmResults<User> users = realm.distinct(User.class, "name");
- 유틸리티 함수 추가
- Realm.isClosed():
하부의 Realm 파일이 열려있는지 확인함 - Realm.isInTransaction():
Realm 파일이 여전히 쓰기 트랜잭션 상태인지 확인함 - RealmQuery.isValid(), RealmList.isValid(), RealmResults.isValid():
하부의 Realm이 닫혀 있거나 데이터가 삭제되었는지 확인함
- Realm.isClosed():
Java 0.85:
New encryption implementation
- 암호화 기능을 구현
- 유틸리티 함수 추가
- Realm.isEmpty():
어떤 데이터를 가졌는지 확인 - RealmEncryptionNotSupportedException 폐기:
모든 기기를 지원함 - Realm.executeTransaction():
RealmException 대신에 RunTimeException을 직접 던지며 예외가 발생하면 자동으로 롤백이 이뤄짐 - RealmQuery.isNull(), RealmQuery.isNotNull():
RealmError 대신 IllegalArgumentException을 던짐
- Realm.isEmpty():
- 전반적으로 안정성이 높아짐
- 다음 버전인 0.86에서는 마이그레이션과 필드를 추가하면서 개발할 수 있는 Dynamic API를 추가할 예정임
Objective-C 0.96
- null을 쓰지 않는 필드에 requiredProperties 추가
@interface OptionalTypes : RLMObject
@property NSString *optionalString;
@property NSString *requiredString;
@property NSData *optionalData;
@property NSDate *optionalDate;
@property NSNumber<RLMInt> *optionalInt;
@property NSNumber<RLMBool> *optionalBool;
@property NSNumber<RLMFloat> *optionalFloat;
@property NSNumber<RLMDouble> *optionalDouble;
@end
@implementation OptionalTypes
+ (NSArray *)requiredProperties {
return @[@"requiredString"];
}
@end
Objective-C 0.96
- Objective-C나 Java 모델에 비해 ?로 간단하게 null을 구현할 수 있음
class OptionalTypes: Object {
dynamic var string: String? = "B"
dynamic var data: NSData? = "C".dataUsingEncoding(NSUTF8StringEncoding)
dynamic var date: NSDate? = NSDate(timeIntervalSince1970: 10)
let int = RealmOptional<Int>(1)
let float = RealmOptional<Float>(2.2)
let double = RealmOptional<Double>(3.3)
let bool = RealmOptional<Bool>(true)
let boolWithNilDefault = RealmOptional<Bool>(nil)
}
Objective-C와 Swift 0.96: 마이그레이션
- Java와 비슷하게 설정에 마이그레이션 객체를 넘긴 후 단계별로 내용을 설정함
- null을 쓸지 쓰지 않을지에 따라 단계가 나뉠 수 있음
// Inside your [AppDelegate didFinishLaunchingWithOptions:]
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// Set the new schema version. This must be greater than the previously used
// version. If you've never set a schema version before, the version is 0,
// so assuming that'd be your first migration, we set it to 1.
config.schemaVersion = 1;
// Set the block which will be called automatically when opening a Realm with a
// schema version lower than the one set above
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
// We haven’t migrated anything yet, so oldSchemaVersion == 0
if (oldSchemaVersion < 1) {
[migration enumerateObjects:Person.className
block:^(RLMObject *oldObject, RLMObject *newObject) {
// convert null-placeholders to actual nils
newObject[@"birthdate"] = [oldObject[@"birthdate"] timeIntervalSince1970] > 0 ? oldObject[@"birthdate"] : nil;
}];
// Note: Even if you don't have to convert placeholder values,
// you still have to provide at least an empty migration block
// when your schema has changes to nullability of properties.
}
};
- Swift와 Objective-C 버전은 다른 프로세스에서도 사용할 수 있는 멀티 프로세스 기능이 지원되고 있으며 Java는 이후 지원할 예정
Q&A
- Q: Realm이 안드로이드의 SQLite보다 빠르다 했는데 iOS의 Core Data와 비교하면?
- A: Core Data도 SQLite DB를 사용하므로 Realm이 빠릅니다.
- Q: DB용도로 사용하긴 좋은데 Json을 파싱한다던가 매핑 기능을 지원하는 부분은?
- A: 다른 라이브러리와 함께 사용해야 하는 데 불편한 부분이 존재하므로 해결책을 고민하고 있습니다.
- Q: 비동기 질의와 관련해서 findAllAsync()를 UI 스레드에서 호출하는지?
- A: UI 스레드에서 호출하면 작업을 멈추지 않고 비동기적으로 호출됩니다.
- Q: onChange()는 작업 스레드에서 불리는지?
- A: 네, 그렇습니다. 간단한 질의는 UI 스레드에서 해도 충분하지만, 복잡한 스레드는 비동기 질의나 비동기 트랜잭션을 쓰시면 좋을 것 같습니다.
컨텐츠에 대하여
이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.