故事是这样的, 小顾在看RN的时候, 看见这么一句话:
不要直接给组件 state 赋值(比如
this.state.hunger = false)来修改状态。使用this.setState()方法才能让 React 知悉状态的变化,从而触发重渲染。直接修改状态变量可能会使界面无法响应!—— 《React中文网 React基础》
因此, 小顾想到了: Objective-C的点语法实际上对应的是getter或setter. 那么如果有一个连续赋值, 是否会引起getter和setter的连续调用, 从而引起(潜在的)调用顺序与预期不一致的问题呢?
小顾于是写了这样的代码做验证:
// MyClass.h
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@property (nonatomic, copy) NSString *str;
@end
// MyClass.m
#import "MyClass.h"
@implementation MyClass
@synthesize str = _str;
- (NSString *)str {
NSLog(@"getter called");
return _str;
}
- (void)setStr:(NSString *)str {
NSLog(@"setter called");
_str = str;
}
@end
// main.m
#import <Foundation/Foundation.h>
#import "MyClass.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyClass *c = [[MyClass alloc] init];
NSString *s = c.str = @"Hello?";
NSLog(@"s = %@", s);
}
return 0;
}
其结果为:
setter called
s = Hello?
即, 只调用了setter, 而未调用getter.
小顾思考了一下才想明白其中的关窍: NSString *s = c.str = @"Hello?";中使用了连续赋值. 赋值运算符(=)是右结合的. 结合性指同一优先级的运算符在表达式中操作的组织方向, 即: 当一个运算对象两侧运算符的优先级别相同时, 运算对象与运算符的结合顺序.
也就是说, 在NSString *s = c.str = @"Hello?";中首先会进行的是c.str = @"Hello?", 这里调用了setter.
然后, 这个语句会被视为: NSString *s = ???, 其中???代表c.str = @"Hello?"的返回值: 赋值运算符=作为一个运算符是有返回值的, 其值为左侧的值.
因此, 此处并没有通过点语法c.str调用到getter, 而是返回了c.str = @"Hello?"的值.
因此, 实际上不存在之前提到的连续赋值对getter/setter调用的影响.