연관(objc setassociatedObject, objc getassociatedObject, objc removeAssociatedObjects) 및 확장 extension

7267 단어 object

 


 


예를 들어 관련은 대상 간에 관계를 맺는 것이다.
확장 코드에 사용하면 저장 필드에 대한 확장을 실현할 수 있지만, 가능한 한 피하는 것이 좋겠다.
 
연관성
연관이란 두 대상을 서로 연결시켜 그 중의 한 대상을 다른 대상의 일부분으로 하는 것을 말한다.연관성은 Mac OS X V10.에서만 사용할 수 있습니다.6 및 이후 버전에서만 사용할 수 있습니다.

클래스의 정의 외에 클래스에 추가 저장 변수를 추가합니다


연결을 사용하면 우리는 클래스의 정의를 수정하지 않고 그 대상에 저장 변수를 추가할 수 있다

 


.이것은 우리가 클래스의 원본에 접근할 수 없을 때나 이진 호환성을 고려할 때 매우 유용하다.연관은 키워드를 기반으로 하기 때문에 우리는 모든 대상에 임의의 연관을 추가할 수 있으며 각각 다른 키워드를 사용하면 된다.연관은 연관된 객체가 연관된 객체의 전체 라이프 사이클에서 사용할 수 있음을 보장합니다(스팸 자동 회수 환경에서도 리소스를 재활용할 수 없음).

연관 생성


Objective-C에 연결할 런타임 함수 만들기:objcsetassociatedObject는 한 객체를 다른 객체와 연관시킵니다.이 함수는 네 가지 인자가 필요합니다. 원본 대상, 키워드, 관련 대상과 관련 정책입니다.물론 이곳의 키워드와 관련 전략은 더 많은 논의가 필요하다.■ 키워드는void 형식의 바늘입니다.모든 관련 키워드는 유일해야 한다.일반적으로 정적 변수를 키워드로 채택한다.■ 관련 정책은 관련 대상이 값을 부여하고 인용을 보류하거나 복제하는 방식으로 관련되어 있음을 나타낸다.그리고 이런 연관성이 원자인지 비원자인지여기의 관련 정책은 속성을 설명할 때와 매우 유사합니다.이런 관련 전략은 미리 정의된 상수를 사용하여 표시한다.다음 코드는 문자열을 하나의 그룹에 연결하는 방법을 보여 줍니다.
목록 7-1 문자열을 그룹에 연결
[cpp] 
view plain
copy
 
static char overviewKey;  
  • NSArray * array =[[NSArray alloc] initWidthObjects:@"One", @"Two", @"Three", nil];  

  • //프레젠테이션의 목적을 위해 initWithFormat: 문자열이 삭제될 수 있도록 합니다
  • NSString * overview = [[NSString alloc] initWithFormat:@"@",@"First three numbers"];  

  • objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);  
  •   

  • [overview release];  
  • //(1)overview는 여전히 사용 가능
  •   
  • [array release];  

  • //(2) overview 사용 불가(1)에서 OBJC 때문에 문자열 오버뷰를 사용할 수 있습니다.ASSOCIATION_RETAIN 정책은 연관된 객체를 보유할 배열을 나타냅니다.수조array가 소각되었을 때, 즉 (2)에서 오버뷰도 방출되어 소각되었다.이 때 오버뷰를 사용하려면 로그를 통해 오버뷰의 값을 출력하려면 실행 중 이상이 발생합니다.

    연관된 객체 가져오기


    연관된 객체를 가져올 때 Objective-C 함수 objc 사용getAssociatedObject.이어서 위 목록 7-1의 코드를 사용하면 다음과 같은 코드를 사용하여 array와 관련된 문자열을 얻을 수 있습니다.
    [cpp] 
    view plain
    copy
     
    NSString * associatedObject = (NSString *)objc_getAssociatedObject(array, &oveviewKey);  

    연결 끊기


    연결 끊기는 objc 사용setassociatedObject 함수, nil 값을 입력하면 됩니다.다음 목록 7-1의 프로그램에서 다음과 같은 코드를 사용하여 문자열 오버뷰와 arry 간의 연결을 끊을 수 있습니다.
    [cpp] 
    view plain
    copy
     
    objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);  
    그 중에서 연결된 대상은nil이며, 이때 관련 전략도 중요하지 않다.함수 objc 사용removeAssociatedObjects는 모든 연결을 끊을 수 있습니다.통상적으로 이 함수를 사용하는 것을 권장하지 않습니다. 왜냐하면 그는 모든 연결을 끊기 때문입니다.대상을 '원시 상태' 로 복원해야 할 때만 이 함수를 사용할 수 있습니다.

    완전한 실례 프로그램


    아래의 프로그램은 앞의 코드를 종합하였다.
    [cpp] 
    view plain
    copy
     
    #import   
  • #import   

  • int main(int argc, const char* argv[])  
  • {  

  •     NSAutoreleasePool * pool = [[NSAutoreleasePool] alloc init];  
    static char overviewKey;  
  •     NSArray *array =[[NSArray alloc] initWidthObjects:@"One", @"Two", @"Three", nil];  

  • //프레젠테이션의 목적을 위해 initWithFormat: 문자열이 삭제될 수 있도록 합니다
  •     NSString * overview = [[NSString alloc] initWithFormat:@"@",@"First three numbers"];  

  •     objc_setAssociatedObject(array, &overviewKey, overview, OBJC_ASSOCIATION_RETAIN);  
  •     [overview release];  
  •     NSString *associatedObject = (NSString *)objc_getAssociatedObject(arrray, &overviewKey);  

  •     NSLog(@"associatedObject:%@", associatedObject);  
        objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);  
  •     [array release];  
  •     [pool drain];  

  • return 0;  
  • }  

  •  
    swift:
    class ObjectWrapper : NSObject {
    
        let value: ThingObjcDoesntLike
    
    
    
        init(value: ThingObjcDoesntLike) {
    
           self.value = value
    
        }
    
    }
    
    
    
    extension NSObject {
    
    
    
        var associatedThing : ThingObjcDoesntLike! {
    
            get {
    
                let wrapper = objc_getAssociatedObject(self, someKey) as ObjectWrapper?
    
                return wrapper?.value
    
            }
    
            set(value) {
    
                let wrapper = ObjectWrapper(value: value)
    
                objc_setAssociatedObject(self, someKey, wrapper, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
    
            }
    
        }    
    
    }
    
    
    
    
    
        var hnk_fetcher : Fetcher<UIImage>! {
    
    
    
            get {
    
    
    
                let wrapper = objc_getAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey) as? ObjectWrapper
    
    
    
                let fetcher = wrapper?.value as? Fetcher<UIImage>
    
    
    
                return fetcher
    
    
    
            }
    
    
    
            set (fetcher) {
    
    
    
                var wrapper : ObjectWrapper?
    
    
    
                if let fetcher = fetcher {
    
    
    
                    wrapper = ObjectWrapper(value: fetcher)
    
    
    
                }
    
    
    
                objc_setAssociatedObject(self, &HanekeGlobals.UIKit.SetImageFetcherKey, wrapper, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
    
    
    
            }
    
    
    
        }
    
    

     
    private var ImageLoaderURLKey: UInt = 0
    
    private var ImageLoaderBlockKey: UInt = 1
    
    
    
    /**
    
        Extension using ImageLoader sends a request, receives image and displays.
    
    */
    
    extension UIImageView {
    
    
    
        // MARK: - properties
    
    
    
        private var URL: NSURL? {
    
            get {
    
                return objc_getAssociatedObject(self, &ImageLoaderURLKey) as? NSURL
    
            }
    
            set(newValue) {
    
                objc_setAssociatedObject(self, &ImageLoaderURLKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
    
            }
    
        }
    
    
    
        private var block: AnyObject? {
    
            get {
    
                return objc_getAssociatedObject(self, &ImageLoaderBlockKey)
    
            }
    
            set(newValue) {
    
                objc_setAssociatedObject(self, &ImageLoaderBlockKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
    
            }
    
        }
    
    

    확장: 이전에 만났던 문제,
    만약 하위 클래스에서 확장을 운용한다면, 하위 클래스 안의 중재 방법은 가능한 한 하위 클래스 주체에 쓰일 것이다
    그렇지 않으면, 부모 클래스에 이 방법을 호출하는 코드가 있고, 효력이 발생하면, 부모 클래스에 다시 불러오지 않은 원본 코드를 호출합니다

    좋은 웹페이지 즐겨찾기