programing

개체에 키 값 관찰자가 연결되어 있는지 확인하는 방법

closeapi 2023. 5. 31. 15:55
반응형

개체에 키 값 관찰자가 연결되어 있는지 확인하는 방법

를 Objective-C에 하는 removeObservers:같은 이 발생합니다.

관자제수찰을 제거할 수.<observerObject> 중한길위여하을요▁the여▁for에 해당합니다."theKeyPath"<objectbeingObserved>관찰자로 등록되지 않았기 때문입니다.

개체에 등록된 관찰자가 있는지 확인할 수 있는 방법이 있습니까?

if (object has observer){
  remove observer
}
else{
  go on my merry way
}

removeObser 호출에 대한 시도 횟수 설정

@try{
   [someObject removeObserver:someObserver forKeyPath:somePath];
}@catch(id anException){
   //do nothing, obviously it wasn't attached because an exception was thrown
}

진짜 문제는 왜 당신이 그것을 관찰하고 있는지 아닌지를 모르는가 하는 것입니다.

관찰되는 개체의 클래스에서 이 작업을 수행하는 경우 중지합니다.관찰하는 것이 무엇이든 간에 계속 관찰할 것으로 예상됩니다.관찰자가 모르는 사이에 알림을 끊으면 무언가가 중단될 것으로 예상합니다. 보다 구체적으로 관찰자가 이전에 관찰한 개체로부터 업데이트를 수신하지 않기 때문에 관찰자의 상태가 오래된 것으로 예상합니다.

관찰 개체의 클래스에서 이 작업을 수행하는 경우에는 관찰 중인 개체를 기억하십시오(또는 관찰 중인 개체가 하나만 있는 경우에는 해당 개체를 관찰하는지 여부).이는 관찰이 동적이고 관련이 없는 두 개체 사이에 있다고 가정합니다. 관찰자가 관찰된 개체를 소유하는 경우 관찰자를 생성하거나 유지한 후 관찰자를 추가하고 관찰된 개체를 해제하기 전에 관찰자를 제거하면 됩니다.

관찰자로 개체를 추가하거나 제거하는 것은 일반적으로 관찰자의 클래스에서 수행되어야 하며 관찰된 개체의 클래스에서는 수행되지 않아야 합니다.

FWIW, 아마도.nil한다면someObject관찰자가 없습니다.하지만 문서화된 것을 보지 못했기 때문에 저는 이 행동을 신뢰하지 않을 것입니다.또한, 나는 읽는 법을 모릅니다.observationInfo특정한 관찰자를 얻기 위해.

이를 위한 유일한 방법은 관찰자를 추가할 때 플래그를 설정하는 것입니다.

를 개체에 할 수 .NSMutableArray다음과 같이:

- (void)addObservedObject:(id)object {
    if (![_observedObjects containsObject:object]) {
        [_observedObjects addObject:object];
    }
}

개체를 관찰하지 않으려면 다음과 같은 작업을 수행할 수 있습니다.

for (id object in _observedObjects) {
    if ([object isKindOfClass:[MyClass class]]) {
        MyClass *myObject = (MyClass *)object;
        [self unobserveMethod:myObject];
    }
}
[_observedObjects removeAllObjects];

단 한 개의 물체가 관찰되지 않을 경우 이 물체를 에서 제거합니다._observedObjects매개 변수:

- (void)removeObservedObject:(id)object {
    if ([_observedObjects containsObject:object]) {
        [_observedObjects removeObject:object];
    }
}

내 생각에는 - 이것은 retainCount 메커니즘과 유사하게 작동합니다.현재로서는 관찰자가 있다고 확신할 수 없습니다.확인해도 : self.observation정보 - 미래에 관찰자가 있을 것인지 여부를 확실히 알 수 없습니다.

리테인 백작처럼.아마도 그 관찰은정보 메소드가 꼭 그렇게 쓸모없는 것은 아니지만, 디버그 목적으로만 사용합니다.

결과적으로 메모리 관리에서처럼 이 작업을 수행하면 됩니다.관찰자를 추가한 경우 - 필요하지 않을 때 제거하면 됩니다.viewWillDisposure/viewWillDisposure 등의 메서드를 사용하는 것을 좋아합니다.예:

-(void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self addObserver:nil forKeyPath:@"" options:NSKeyValueObservingOptionNew context:nil];
}

-(void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [self removeObserver:nil forKeyPath:@""];
}

그리고 특정 검사가 필요한 경우 - 관찰자 배열을 처리하는 자체 클래스를 구현하고 검사에 사용합니다.

[someObject observationInfo]nil참관인이 없는 경우

if ([tableMessage observationInfo] == nil)
{
   NSLog(@"add your observer");
}
else
{
  NSLog(@"remove your observer");

}

관찰자 패턴의 요점은 관찰된 클래스를 "밀봉"할 수 있도록 하는 것입니다. 관찰되는지 여부를 모르거나 신경 쓰지 않습니다.당신은 분명히 이 패턴을 깨려고 합니다.

왜요?

여러분이 겪고 있는 문제는 여러분이 관찰되지 않을 때 관찰되고 있다고 가정하고 있다는 것입니다.이 개체는 관찰을 시작하지 않았습니다.클래스에서 이 프로세스를 제어하려면 알림 센터를 사용하는 것이 좋습니다.그러면 클래스에서 데이터를 관측할 수 있는 시기를 완전히 제어할 수 있습니다.따라서 누가 보고 있는지는 중요하지 않습니다.

저는 트라이 캐치 솔루션의 팬이 아니기 때문에 대부분의 경우 해당 클래스 내에서 특정 알림에 대한 구독 및 구독 취소 방법을 만듭니다.예를 들어 다음 두 가지 방법은 글로벌 키보드 알림에 개체를 서브스크라이브하거나 서브스크라이브하지 않습니다.

@interface ObjectA : NSObject
-(void)subscribeToKeyboardNotifications;
-(void)unsubscribeToKeyboardNotifications;
@end

이러한 메소드 내에서 다음과 같이 가입 상태에 따라 true 또는 false로 설정된 개인 속성을 사용합니다.

@interface ObjectA()
@property (nonatomic,assign) BOOL subscribedToKeyboardNotification
@end

@implementation

-(void)subscribeToKeyboardNotifications {
    if (!self.subscribedToKeyboardNotification) {
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardShow:) name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(onKeyboardHide:) name:UIKeyboardWillHideNotification object:nil];
        self.subscribedToKeyboardNotification = YES;
    }
}

-(void)unsubscribeToKeyboardNotifications {
    if (self.subscribedToKeyboardNotification) {
        [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillShowNotification object:nil];
        [[NSNotificationCenter defaultCenter]removeObserver:self name:UIKeyboardWillHideNotification object:nil];
        self.subscribedToKeyboardNotification = NO;
    }
}
@end

Adam의 답변 외에도, 저는 이와 같은 매크로를 사용할 것을 제안합니다.

#define SafeRemoveObserver(sender, observer, keyPath) \
@try{\
   [sender removeObserver:observer forKeyPath:keyPath];\
}@catch(id anException){\
}

용례

- (void)dealloc {
    SafeRemoveObserver(someObject, self, somePath);
}

롱 스토리 쇼트

가지고 가다NSObject여기서 카테고리를 지정하고 다음과 같이 사용합니다.

if ([observable tdw_hasObserver:observer forKeyPath:@"key.path" context:nil error:nil]) {
    [observable removeObserver:observer forKeyPath:@"key.path"];
} else {
    // go on your merry way
}

공개 API 접근 방식

다른 관찰자가 없는 많은 Foundation 클래스의 경우, 당신은 그냥 확인할 수 있습니다.observationInfo 불투명한 경우 포인터합니다.void *포인터 그렇지 않으면:

if (observable.observationInfo) {
    [observable removeObserver:observer forKeyPath:@"key.path"];
} else {
    // go on your merry way
}

이것은 에는 작동하지 않습니다.UIKit사용자 자신이 둘 이상의 관찰자를 사용하는 클래스 및 시나리오.


개인 API 접근 방식

개인 API를 조작해도 괜찮으시다면 어떤 개체든 의 속성을 사용하여 관찰자 데이터를 가리키는 불투명한 개체를 제공할 수 있습니다.후드 아래에서 포인터는 개체를 유지하며, 이 개체는 단일 구독을 설명하는 특수 데이터 구조(의 모든 호출은 모든 인수가 동일하더라도 배열에 새 인스턴스를 생성함)를 포함합니다.준수 메모리 레이아웃(최소한 이 답변을 작성할 때)은 다음과 같습니다.

@interface NSKeyValueObservance: NSObject {
    id _observer;
    NSKeyValueProperty *_property;
    void *_context;
    id originalObservable;
}

이러한 변수의 조합은 찾고 있는 정보입니다.물론 이 데이터는 개인 API이기 때문에 안정적으로 추출할 수는 없지만 몇 가지 단순한 가정을 통해 이 계약은 오래 전부터 유효합니다.

  1. observationInfo가 있어야 합니다.NSArray관측치 데이터를 보관하는 ivar;
  2. _observer,_property그리고._contextivar 이름 그대로;
  3. _context그리고._observer포인터 주소로 원하는 데이터와 비교할 수 있습니다.
  4. _propertyivar has_keyPath유형의NSString원하는 키 경로와 비교합니다.

그런 점을 염두에 두고 확장할 수 있습니다.NSObject범주를 사용하여 특정 조합의 존재 여부를 확인하는 편리한 방법을 구현합니다.

나는 나만의 구현을 공유하는 것에 대해 개의치 않지만, 단일 SO 답변에 맞추기에는 약간 무리가 있습니다.당신은 그것을 내 기스트 페이지에서 확인할 수 있습니다.이 구현에서는 이름 및 (때로는) 유형별로 ivar 조회를 수행합니다.아이바 오프셋을 직접 사용하는 것보다 다소 안전하지만 여전히 매우 취약합니다.API의 개인적인 부분이 어쨌든 변경되는 경우, 구현이 중단되지 않을 것이라고 확신하지 않습니다.

다음은 사용 방법에 대한 간단한 예입니다.

NSObject *observable = [NSObject new];
NSObject *observer = [NSObject new];
void *observerContext = &observerContext;

[observable addObserver:observer forKeyPath:@"observationInfo" options:NSKeyValueObservingOptionNew context:observerContext];
[observable addObserver:observer forKeyPath:@"observationInfo" options:NSKeyValueObservingOptionNew context:nil];
[observable addObserver:observer forKeyPath:@"observationInfo" options:NSKeyValueObservingOptionNew context:observerContext];

// Removes only 2 observances (subscriptions) where all parts matches (context, keyPath and observer instance)
while ([observable tdw_hasObserver:observer forKeyPath:@"observationInfo" context:observerContext error:nil]) {
    [observable removeObserver:observer forKeyPath:@"observationInfo" context:observerContext];
}

두 문장으로 된 문서

한다면context및/또는keyPath주장은nil구현에서는 해당 관측치 변수의 값이 검색 기준을 충족한다고 가정합니다.

(예상) 오류가 발생하면 메서드가 다음을 반환합니다.NO에 오류 세부 정보를 기록합니다.error개체(해당 포인터가 제공된 경우).예상되는 오류에는 개인 API의 일부 사소한 변경 사항이 포함됩니다(그러나 변경 사항과는 거리가 멉니다).

또한 이 코드를 프로덕션 앱에서 사용하지 않는 것이 좋습니다. 디버깅에는 보통 충분합니다.

언급URL : https://stackoverflow.com/questions/1582383/how-can-i-tell-if-an-object-has-a-key-value-observer-attached

반응형