문제

애플리케이션의 여러 위치에서 싱글톤 패턴을 사용하고 있는데 다음 위치에서 메모리 누수 오류가 발생합니다. clang 코드를 분석할 때

static MyClass *_sharedMyClass;
+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      [[self alloc] init];
  }
  return _sharedMyClass;
}

// clang error: Object allocated on line 5 is no longer referenced after this point and has a retain count of +1 (object leaked)

나는 이 설정을 사용하고 있습니다. scan-build:

scan-build -v -v -v -V -k xcodebuild

저는 싱글톤의 코드가 괜찮다고 확신합니다. 결국 이는 여기 Stack Overflow와 Apple 문서에서 참조된 코드와 동일합니다. 하지만 메모리 누수 경고를 정리하여 스캔하고 싶습니다. 빌드가 성공을 반환합니다.

도움이 되었습니까?

해결책

나는 매우 밀도가 높을 지 모르지만 확실히 당신의 줄 5

[[self alloc] init];

포함 된 클래스 유형의 객체를 할당하고 즉시 버릴까요? 당신은 원하지 않습니까?

_sharedMyClass = [[self alloc] init];

?

다른 팁

Apple은 이후 업데이트를 했습니다. 권장되는 싱글톤 코드 정적 분석기를 통과하려면 다음을 수행하세요.

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedManager] retain];
}

지금 +sharedManager 슈퍼에 전화해 -allocWithZone: 그리고 반환을 할당합니다. -init, 그리고 싱글턴의 -allocWithZone: 단지 유지된 sharedInstance를 반환합니다.

편집하다:

+allocWithZone:에 유지하는 이유는 무엇입니까?

+allocWithZone:MyGizmoClass를 사용하는 누군가가 [MyGizmoClass sharedManager] 대신 [[MyGizmoClass alloc] init]를 호출하여 싱글톤을 우회할 수 있기 때문에 재정의되었습니다.+alloc은 항상 유지 횟수가 +1인 객체를 반환할 것으로 예상되기 때문에 유지됩니다.

+alloc에 ​​대한 모든 호출은 -release 또는 -autorelease와 균형을 이루어야 하므로 +allocWithZone:에 보유하지 않으면 공유 인스턴스가 잠재적으로 다른 사용자 아래에서 할당 취소될 수 있습니다.

당신은 단순한 단일 메드, GCD 기반 싱글 톤 구현 (및 10.6+ 만 해당)에 관심이있을 수 있습니다. Mike Ash의 사이트:

+ (id)sharedFoo
{
    static dispatch_once_t pred;
    static Foo *foo = nil;

    dispatch_once(&pred, ^{ foo = [[self alloc] init]; });
    return foo;
}

당신은 참조하고 있습니다 self 수업 방법에서! 큰 아니요! 둘째, 당신은 전화하고 있습니다 [[self alloc] init] 그리고 인스턴스를 버리는 것입니다. 수업 방법에 싱글 톤 참조를 할당해야하며 init 내가 당신이하고 있다고 추측하는 것처럼. 다음으로, 그것을 보장하는 것은 없습니다 _sharedMyClass 0으로 초기화됩니다. 명시 적으로 초기화해야합니다 nil.

static MyClass *_sharedMyClass = nil;

+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      _sharedMyClass = [[MyClass alloc] init];
  }
  return _sharedMyClass;
}

당신도 아마 거기에 이것도 있었을 것입니다 ...

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [super allocWithZone:zone];
            return sharedInstance;  // assignment and return on first allocation
        }
    }
    return nil; // on subsequent allocation attempts return nil
}

이 init에 저장하지 않은 이유는 Alloc이 불리는 방법에 저장했기 때문입니다. 이것이 Apple이 예제에서 가지고있는 패턴입니다. Init에서도 값을 저장하면 모든 것이 정상이며 경고가 사라집니다. 나는 AllocwithZone 구현을 단독으로 남겨 두었습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top