#ios #objective-c #key-value-observing #nsoperation
#iOS #objective-c #наблюдение за значением ключа #nsoperation
Вопрос:
При наблюдении за isExecuted
свойством NSOperation
объекта я вижу некоторое неожиданное поведение. Я регистрирую наблюдателя с параметрами NSKeyValueObservingOptionNew
и. NSKeyValueObservingOptionOld
Я бы ожидал, что последнее наблюдение изменит словарь для isExecuting
, чтобы иметь значение @YES
для NSKeyValueChangeNewKey
и @NO
для NSKeyValueChangeOldKey
. Тем не менее, я вижу, что эти значения меняются местами. Все остальные наблюдения выполняются так, как ожидалось. Я делаю что-то не так или, возможно, в SDK есть ошибка? Я использую Xcode 8 с iOS SDK версии 10.0, а целевая платформа моего проекта — 8.0.
Ниже приведен неудачный случай XCTest, чтобы проиллюстрировать неожиданное поведение, которое я вижу.
#import <XCTest/XCTest.h>
@interface TestNSOperationKVO : XCTestCase
@end
@implementation TestNSOperationKVO {
NSMutableArray<NSDictionary *> *changes;
}
NSString *kKeyPath = @"keyPath";
NSString *kChange = @"change";
- (void)setUp {
[super setUp];
changes = [NSMutableArray array];
}
- (void)tearDown {
[super tearDown];
}
- (void)testIsExecutingKVO {
NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{}];
[op addObserver:self forKeyPath:NSStringFromSelector(@selector(isExecuting)) options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:NULL];
[op addObserver:self forKeyPath:NSStringFromSelector(@selector(isFinished)) options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:NULL];
[op start];
XCTAssertEqual(changes.count, 3);
XCTAssert([@"isExecuting" isEqualToString:changes[0][kKeyPath]]);
XCTAssertEqual(changes[0][kChange][NSKeyValueChangeOldKey], @NO);
XCTAssertEqual(changes[0][kChange][NSKeyValueChangeNewKey], @YES);
XCTAssert([@"isExecuting" isEqualToString:changes[1][kKeyPath]]);
// this fails
XCTAssertEqual(changes[1][kChange][NSKeyValueChangeOldKey], @YES);
// this fails
XCTAssertEqual(changes[1][kChange][NSKeyValueChangeNewKey], @NO);
XCTAssert([@"isFinished" isEqualToString:changes[2][kKeyPath]]);
XCTAssertEqual(changes[2][kChange][NSKeyValueChangeOldKey], @NO);
XCTAssertEqual(changes[2][kChange][NSKeyValueChangeNewKey], @YES);
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
[changes addObject:@{kKeyPath: keyPath, kChange: change}];
}
@end