RAC中的宏定义魔法

https://onevcat.com/2014/01/black-magic-in-macro/

1. #的作用

2. ##的作用

3. VA_ARGS的作用

4. RAC()

4.1 函数功能

RAC(),有两种调用方式,一个是两个参数,一个是三个参数的。函数的第一个参数代表着要绑定的对象,第二个参数要绑定的对象的属性,第三个参数代表当追踪的结果为nil时,应该赋予的值。

这里就有一个很有趣的问题,ReactiveCocoa是如何做到用一个函数宏,自动识别参数个数,并调用正确的函数的呢?

Read more   2019/01/21 00:13 上午 posted in  iOS

Realm学习笔记

  • Useful文章

https://www.jianshu.com/p/6704afc62d6c

Realm 核心数据库引擎探秘

1. 模型定义

参照官网的demo,建立如下两个类:

@interface Dog : RLMObject
@property NSString *name;
@property NSData   *picture;
@property NSInteger age;
@end
@implementation Dog
@end
RLM_ARRAY_TYPE(Dog)
@interface Person : RLMObject
@property NSString             *name;
@property RLMArray<Dog *><Dog> *dogs;
@end
@implementation Person
@end
tips

1. 需要继承RLMObject
2. 所有的属性都不需要写任何的描述符,原子性,strong, assign等
3. Array类型需要用RLMArray
4. 使用Array 需要定义 RLM_ARRAY_TYPE , 这个定义放在类前类后都可以。

2.CRUD

Realm采用了MVCC设计架构,因此读写操作是不互斥的。但是写操作最好在一个Seperate thread中执行,否则会降低效率。

2.1 创建(Create)

// (1) Create a Dog object and then set its properties
    Dog *myDog = [[Dog alloc] init];myDog.name = @"Rex";myDog.age = 10;
// (2) Create a Dog object from a dictionary
    Dog *myOtherDog = [[Dog alloc] initWithValue:@{@"name" : @"Pluto", @"age" : @3}];
// (3) Create a Dog object from an array
    Dog *myThirdDog = [[Dog alloc] initWithValue:@[@"Pluto", @3]];

写入数据库

    // Get the default Realm
    RLMRealm *realm = [RLMRealm defaultRealm];
    // You only need to do this once (per thread)
    
    // Add to Realm with transaction
    [realm beginWriteTransaction];
    [realm addObject:province];
    [realm commitWriteTransaction];

2.2 查询(Retrieve)

// 使用断言字符串查询
    RLMResults<ProvinceEntity *> *provinceArray = [ProvinceEntity objectsWhere:@"shortName = '江苏'"];
    // 使用 NSPredicate 查询
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"shortName = '江苏'"];
    provinceArray = [ProvinceEntity objectsWithPredicate:pred];

如果有多条件的话,可以用and,也可以分布查询,从查询结果中再做查询,支持链式查询:

RLMResults<Dog *> *tanDogs = [Dog objectsWhere:@"color = '棕黄色'"];
RLMResults<Dog *> *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH '大'"];

RLMResults允许您指定一个排序标准,从而可以根据一个或多个属性进行排序。比如说,下列代码将上面例子中返回的狗狗根据名字升序进行排序:

// 排序名字以“大”开头的棕黄色狗狗
RLMResults<Dog *> *sortedDogs = [[Dog objectsWhere:@"color = '棕黄色' AND name BEGINSWITH '大'"] sortedResultsUsingProperty:@"name" ascending:YES];

2.3 更新(Update)

  • 你可以找到具体的一条数据然后去更新:
    RLMResults<ProvinceEntity *>* provinceArray=[ProvinceEntity allObjects];
    [[RLMRealm defaultRealm] transactionWithBlock:^{
        ProvinceEntity *province=[provinceArray firstObject];
        province.shortName=@"浙江";
    }];
  • 你也可以设置一个主键,根据主键去更新,更新需要拥有一个主键---Primary Keys:
// Creating a book with the same primary key as a previously saved 
bookBook *cheeseBook = [[Book alloc] init];
cheeseBook.title = @"Cheese recipes";
cheeseBook.price = @9000;
cheeseBook.id = @1;
// Updating book with id = 1
[realm beginWriteTransaction];
[realm addOrUpdateObject:cheeseBook];
[realm commitWriteTransaction];

2.4 删除(Delete)

  • 单条记录删除
// Delete an object with a transaction
[realm beginWriteTransaction];
[realm deleteObject:cheeseBook];
[realm commitWriteTransaction];
  • 多条记录删除
    [[RLMRealm defaultRealm] transactionWithBlock:^{
        [[RLMRealm defaultRealm] deleteObjects:result];
    }];
  • 全部删除:
// Delete an object with a transaction
    [[RLMRealm defaultRealm] transactionWithBlock:^{
        [[RLMRealm defaultRealm] deleteAllObjects];
    }];

3.进阶使用

  • 非空字段(Required properties)

By default, NSString *, NSData *, and NSDate * properties allow you to set them to nil. If you want to require that a value be present, override the +requiredProperties method on your RLMObject subclass.

For example, with the following model definition, trying to set the person’s name to nil will throw an exception, but setting their birthday to nil is allowed:

@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthday;
@end

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

例外:RLMObject subclass properties always can be nil, and thus cannot be included in requiredProperties. and RLMArray does not support storing nil.

  • 主键

Override +primaryKey to set the model’s primary key. Declaring a primary key allows objects to be looked up and updated efficiently and enforces uniqueness for each value. Once an object with a primary key is added to a Realm, the primary key cannot be changed.

@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end

@implementation Person
+ (NSString *)primaryKey {
    return @"id";
}
@end
  • 索引字段

To index a property, override +indexedProperties. Like primary keys, indexes make writes slightly slower, but makes queries using comparison operators faster. (It also makes your Realm file slightly larger, to store the index.) It’s best to only add indexes when you’re optimizing the read performance for specific situations.

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book
+ (NSArray *)indexedProperties {
    return @[@"title"];
}
@end
  • 忽略字段

If you don’t want to save a field in your model to its Realm, override +ignoredProperties. Realm won’t interfere with the regular operation of these properties; they’ll be backed by ivars, and you can freely override their setters and getters.

@interface Person : RLMObject
@property NSInteger tmpID;
@property (readonly) NSString *name; // read-only properties are automatically ignored
@property NSString *firstName;
@property NSString *lastName;
@end

@implementation Person
+ (NSArray *)ignoredProperties {
    return @[@"tmpID"];
}
- (NSString *)name {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end
  • 默认值

Override +defaultPropertyValues to provide default values every time an object is created.

@interface Book : RLMObject
@property float price;
@property NSString *title;
@end

@implementation Book
+ (NSDictionary *)defaultPropertyValues {
    return @{@"price" : @0, @"title": @""};
}
@end

4. 特性

5. 疑问

为什么要这样直接继承不可以吗?是不支持吗?

// Base Model
@interface Animal : RLMObject
@property NSInteger age;
@end
@implementation Animal
@end

// Models composed with Animal
@interface Duck : RLMObject
@property Animal *animal;
@property NSString *name;
@end
@implementation Duck
@end

@interface Frog : RLMObject
@property Animal *animal;
@property NSDate *dateProp;
@end
@implementation Frog
@end

// Usage
Duck *duck =  [[Duck alloc] initWithValue:@{@"animal" : @{@"age" : @(3)}, @"name" : @"Gustav" }];
2018/03/21 19:57 下午 posted in  iOS