본문 바로가기
IOS (Swift, Objective-c)

[IOS] Objective-C 에서 Realm 사용하기

by bryan.oh 2022. 2. 5.
반응형

Realm
Objective-C, Swift 에서 사용하기

 

직접 테스트 해보시려면 아래 두 링크를 참고하세요.

한 프로젝트에서 Objective-C, Swift 둘 다 사용하기

[IOS (Swift, Objective-c)] - [IOS] Objective-c, Swift 혼합 프로젝트

CocoaPod 설치, Realm 설치

[IOS (Swift, Objective-c)] - [IOS] CocoaPod 설치. 프로젝트 설정하기

 

[참고] realm 이란?

 

Objective-C 에서 Realm 사용하기

Objective-C ViewController.m 에서
(전체 소스는 하단에 접은글에 있습니다.)

import

#import <Realm/Realm.h>

 

Model 객체 정의

// Define your models
@interface User : RLMObject
@property NSString *name;
@property NSInteger age;
@end

@implementation User
@end

User 라는 모델을 만들었습니다.

만약에 primaryKey 가 필요하다면, 

// Define your models
@interface User : RLMObject
@property NSString *id;
@property NSString *name;
@property NSInteger age;
@end

@implementation User
+ (NSString *)primaryKey {
    return @"id";
}
@end
참고1
처음에 primaryKey 없이 사용하다가 데이터가 들어가 있는 상태에서 primaryKey 를 추가하면 오류가 발생합니다.
기존에 있던 데이터들에 primaryKey 를 넣을 수 없기 때문이죠.  (하단에 Migration 링크 참조)
참고2
auto-incrementing property 는 없다고 합니다. UUID 를 사용하면 될거같아요.
Auto-incrementing properties: Realm has no mechanism for thread-safe/process-safe auto-incrementing properties commonly used in other databases when generating primary keys. However, in most situations where a unique auto-generated value is desired, it isn’t necessary to have sequential, contiguous, integer IDs. A unique string primary key is typically sufficient. A common pattern is to set the default property value to NSUUID().UUIDString to generate unique string IDs.
Another common motivation for auto-incrementing properties is to preserve order of insertion. In some situations, this can be accomplished by appending objects to a List or by using a createdAt property with a default value of Date().

 

Default property values

@implementation User
+ (NSDictionary *)defaultPropertyValues {
    return @{@"age" : @10, @"name": @""};
}
@end

Required ( = Not Null ) 설정

@implementation User
+ (NSArray *)requiredProperties {
    return @[@"id", @"name"];
}
@end

Index 설정

@implementation User
+ (NSArray *)indexedProperties {
    return @[@"name"];
}
@end

커스텀 함수

@implementation User
- (NSString *)name {
    return [NSString stringWithFormat:@"%@ %li", self.name, self.age];
}
@end

 

 

Realm file 초기화 ( 전체 초기화 )

NSError *error = nil;
[RLMRealm deleteFilesForConfiguration:[RLMRealmConfiguration defaultConfiguration] error:&error];
if (error) {
    NSLog(@"%@", error);
}

 

 

입력할 데이터 준비

User *user = [[User alloc] init];
user.id = [[NSUUID UUID] UUIDString];
user.name = @"hello";
user.age = 10;

다른 방법

// init with value
User *user = [[User alloc] initWithValue:@{@"id": [[NSUUID UUID] UUIDString], @"name": @"bryan", @"age": @20}];

 

입력 (addObject)

// 입력
[realm beginWriteTransaction];
[realm addObject:user];
[realm commitWriteTransaction];

다른 방법

[realm transactionWithBlock:^{
    [realm addObject:user];
}];

 

조회

// 전체 데이터 조회
RLMResults<User *> *allUsers = [User allObjects];
NSLog(@"Number of all users: %li", (unsigned long)allUsers.count);

// 조건 조회
RLMResults *results = [User objectsInRealm:realm where:@"age > 5"];
NSLog(@"Number of users: %li", (unsigned long)results.count);

// 객체 탐색
for(User *user in results){
    NSLog(@"name = %@, age = %li", user.name, user.age);
}

Operators

  • ==, <=, <, >=, >, !=, BETWEEN 은 int, long, long long, float, double, NSDate 타입에서 사용할 수 있음
  • ==, != 은 정확한 값 비교. 예) [Employee objectsWhere:@"company == %@", company]
  • NSString, NSData 는 ==, !=, BEGINSWITH, CONTAINS, ENDSWITH 를 사용할 수 있음.
  • LIKE 도 사용할 수 있는데, 와일드 카드로 * 과 ? 가 있습니다. * 은 mysql의 % 와 같고, ? 는 _ 와 같습니다.
    예) value LIKE '?bc*' 는 앞의 어떤 한글자가 있고 두번째,세번째 값은 bc 이고 뒤에 무엇이 있든지 조회함.
  • compound operators : AND, OR, NOT
  • IN : name IN {'Lisa', 'Spike', 'Hachi'}
  • nil 도 사용 가능 : 예) [Company objectsWhere:@"ceo == nil"]
  • ANY 가능 : 예) ANY student.age < 21  나이가 21세 미만인 데이터가 하나라도 존재하면 true
  • 집합 표현 : @count, @min, @max, @sum, @avg : 예) [Company objectsWhere:@"employees.@count > 5"]
    subquery 사용 예) SUBQUERY(…).@count

objectsWhere 의 더많은 참고 링크

 

정렬

RLMResults *results = [[User objectsInRealm:realm where:@"age > 5"] sortedResultsUsingKeyPath:@"age" ascending:YES];

 

LIMIT

limit 는 없습니다. Realm 은 lazy Query 기 때문에, for문을 사용하면 됩니다. 성능상 전혀 문제가 없습니다. 

예를들어, 5개만 가져오려면, for 문을 5번만 돌면 됩니다.

RLMResults<User *> *users = [User allObjects];
for (NSInteger i = 0; i < 5; i++) {
    User *user = users[i];
    // ...
}

 

업데이트 (다른 쓰레드에서)

// 다른 쓰레드에서 업데이트
dispatch_async(dispatch_queue_create("background", 0), ^{
    @autoreleasepool {
        User *user = [[User objectsWhere:@"name contains 'bryan'"] firstObject];
        NSLog(@"bryan's id is %@", user.id);
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm beginWriteTransaction];
        user.age = 30;
        [realm commitWriteTransaction];
    }
});

이름이 bryan 을 포함하는 것들 중 첫번째 항목에서 age 를 30 으로 변경합니다.

조회된 데이터가 없다면, NSLog 는 다음과 같이 출력 됩니다.

bryan's id is (null)

 

삭제

단건 삭제

// Delete an object with a transaction
[realm beginWriteTransaction];
[realm deleteObject:[[allUsersByAge objectsWhere:@"name == 'hello'"] firstObject]];
[realm commitWriteTransaction];

여러건 삭제

[realm transactionWithBlock:^{
    [realm deleteObjects:[allUsersByAge objectsWhere:@"age < 20"]];
}];

전체 삭제

[realm beginWriteTransaction];
[realm deleteAllObjects];
[realm commitWriteTransaction];

 

 

여기까지, 기본적인 사용법이었습니다.

 

테스트 했던, 전체 소스

더보기

#import "ObjcTestController.h"

#import <Realm/Realm.h>

// Define your models

@interface User : RLMObject

@property NSString *id;

@property NSString *name;

@property NSInteger age;

@end

 

@implementation User

+ (NSString *)primaryKey {

    return @"id";

}

@end

 

@interface ObjcTestController ()

@end

 

@implementation ObjcTestController

 

- (void)viewDidLoad {

    [super viewDidLoad];

    

//    NSError *error = nil;

//    [RLMRealm deleteFilesForConfiguration:[RLMRealmConfiguration defaultConfiguration] error:&error];

//    if (error) {

//        NSLog(@"%@", error);

//    }

                

    User *user = [[User alloc] init];

    user.id = [[NSUUID UUID] UUIDString];

    user.name = @"hello";

    user.age = 10;

    NSLog(@"User Name: %@", user.name);

    

    RLMRealm *realm = [RLMRealm defaultRealm];

    

    // 입력

    [realm beginWriteTransaction];

    [realm addObject:user];

    [realm commitWriteTransaction];

    

    User *userInit = [[User alloc] initWithValue:@{@"id": [[NSUUID UUID] UUIDString], @"name": @"bryan", @"age": @20}];

    // 다른 방법의 transaction

    [realm transactionWithBlock:^{

        [realm addObject:userInit];

    }];  

   

    // 조회

    RLMResults *results = [User objectsInRealm:realm where:@"age > 5"];

    NSLog(@"Number of users: %li", (unsigned long)results.count);

    

    // 전체

    RLMResults<User *> *allUsers = [User allObjects];

    NSLog(@"Number of all users: %li", (unsigned long)allUsers.count);

 

    RLMResults<User *> *allUsersByAge = [allUsers sortedResultsUsingKeyPath:@"age" ascending:YES];

    for(User *user in allUsersByAge){

        NSLog(@"name = %@, age = %li", user.name, user.age);

    }

    NSLog(@"Number of all users: %li", (unsigned long)allUsersByAge.count);

    

    // Delete an object with a transaction

    [realm beginWriteTransaction];

    [realm deleteObject:[[allUsersByAge objectsWhere:@"name == 'hello'"] firstObject]];

    [realm commitWriteTransaction];

    NSLog(@"Number of all users after delete : %li", (unsigned long)allUsersByAge.count);

    

    [realm transactionWithBlock:^{

        [realm deleteObjects:[allUsersByAge objectsWhere:@"age < 20"]];

    }];

    

//    // Delete all objects from the realm

//    [realm beginWriteTransaction];

//    [realm deleteAllObjects];

//    [realm commitWriteTransaction];

    

    // 다른 쓰레드에서 업데이트

    dispatch_async(dispatch_queue_create("background", 0), ^{

        @autoreleasepool {

            User *user = [[User objectsWhere:@"name contains 'bryan'"] firstObject];

            NSLog(@"bryan's id is %@", user.id);

            RLMRealm *realm = [RLMRealm defaultRealm];

            [realm beginWriteTransaction];

            user.age = 30;

            [realm commitWriteTransaction];

        }

    });

}

@end

 

참고 1

예제 소스에 있는 User 는 여러군데에서 사용될 수 있으니 따로 빼도록 합니다.
1. New Group 생성 (예제에서는 명칭은 Models 로 합니다.)

2. 생성된 group 에서 New File 클릭 > Header File 생성

3. Models/User.h 파일 내용

//
//  User.h
//  RealmTest
//
//  Created by USER on 2022/02/05.
//

#ifndef User_h
#define User_h

// Define your models
@interface User : RLMObject
@property NSString *id;
@property NSString *name;
@property NSInteger age;
@end

@implementation User
+ (NSString *)primaryKey {
    return @"id";
}
@end

#endif /* User_h */

4. ObjcTestController.m 에서

 

참고 2

 

728x90
반응형

댓글