๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿฅ– Bread Basics/Obj-c

Obj-C ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ - ์—ฐ๊ด€ ์ฐธ์กฐ(Associative References)

by BreadDev 2025. 4. 14.
728x90

์•ˆ๋…•ํ•˜์„ธ์š”! ์ด๋ฒˆ์—๋Š” Objective-C์˜ ์—ฐ๊ด€ ์ฐธ์กฐ(Associative References)์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ž˜์Šค ์„ ์–ธ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ์ฒด์— ์ €์žฅ ๊ณต๊ฐ„์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์–ด ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ ์—ฐ๊ด€ ์ฐธ์กฐ๋ž€?

OS X v10.6๋ถ€ํ„ฐ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฐ๊ด€ ์ฐธ์กฐ๋Š” ๊ธฐ์กด ํด๋ž˜์Šค์— ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•ฉ๋‹ˆ๋‹ค. ์—ฐ๊ด€ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ž˜์Šค ์„ ์–ธ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ์ฒด์— ์ €์žฅ ๊ณต๊ฐ„์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฐ๊ด€ ์ฐธ์กฐ(Associative References): ๊ธฐ์กด ํด๋ž˜์Šค์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ๋Ÿฐํƒ€์ž„์— ๊ฐ์ฒด์— ๋™์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

  • ํด๋ž˜์Šค์˜ ์†Œ์Šค ์ฝ”๋“œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ
  • ๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜ธํ™˜์„ฑ ์ด์œ ๋กœ ๊ฐ์ฒด ๋ ˆ์ด์•„์›ƒ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ

์—ฐ๊ด€ ์ฐธ์กฐ๋Š” ํ‚ค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๊ฐ์ฒด์—๋“  ์„œ๋กœ ๋‹ค๋ฅธ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ๋งŒํผ ๋งŽ์€ ์—ฐ๊ด€์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์—ฐ๊ด€ ๊ด€๊ณ„๋Š” ์†Œ์Šค ๊ฐ์ฒด์˜ ์ˆ˜๋ช… ๋™์•ˆ ์ ์–ด๋„ ์—ฐ๊ด€๋œ ๊ฐ์ฒด๊ฐ€ ์œ ํšจํ•˜๊ฒŒ ์œ ์ง€๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์—ฐ๊ด€ ๊ด€๊ณ„ ์ƒ์„ฑํ•˜๊ธฐ

Objective-C ๋Ÿฐํƒ€์ž„ ํ•จ์ˆ˜ objc_setAssociatedObject๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•œ ๊ฐ์ฒด์™€ ๋‹ค๋ฅธ ๊ฐ์ฒด ์‚ฌ์ด์— ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ๋„ค ๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค:

  1. ์†Œ์Šค ๊ฐ์ฒด: ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์ถ”๊ฐ€ํ•  ๊ฐ์ฒด
  2. ํ‚ค: ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ๊ณ ์œ  ์‹๋ณ„์ž
  3. ๊ฐ’: ์—ฐ๊ด€์‹œํ‚ฌ ๊ฐ์ฒด
  4. ์—ฐ๊ด€ ์ •์ฑ… ์ƒ์ˆ˜: ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ํŠน์„ฑ์„ ์ •์˜

ํ‚ค(Key): ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์‹๋ณ„ํ•˜๋Š” void ํฌ์ธํ„ฐ์ž…๋‹ˆ๋‹ค. ๊ฐ ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ํ‚ค๋Š” ๊ณ ์œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์ •์  ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์—ฐ๊ด€ ์ •์ฑ…(Association Policy): ์—ฐ๊ด€๋œ ๊ฐ์ฒด๊ฐ€ ํ• ๋‹น(assign), ์œ ์ง€(retain) ๋˜๋Š” ๋ณต์‚ฌ(copy)๋˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์›์ž์ (atomic)์œผ๋กœ ๋งŒ๋“ค์–ด์ง€๋Š”์ง€ ๋น„์›์ž์ (non-atomic)์œผ๋กœ ๋งŒ๋“ค์–ด์ง€๋Š”์ง€ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒจํ„ด์€ ์„ ์–ธ๋œ ํ”„๋กœํผํ‹ฐ์˜ ์†์„ฑ๊ณผ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋Š” ๋ฐฐ์—ด๊ณผ ๋ฌธ์ž์—ด ์‚ฌ์ด์— ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค:

static char overviewKey;
 
NSArray *array =
    [[NSArray alloc] initWithObjects:@"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 ์ •์ฑ…์ด ๋ฐฐ์—ด์ด ์—ฐ๊ด€๋œ ๊ฐ์ฒด๋ฅผ ์œ ์ง€ํ•˜๋„๋ก ์ง€์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ž์—ด overview๋Š” ์—ฌ์ „ํžˆ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐฐ์—ด์ด ํ•ด์ œ๋  ๋•Œ(ํฌ์ธํŠธ 2์—์„œ), overview๋„ ํ•ด์ œ๋˜์–ด ์ด ๊ฒฝ์šฐ์—๋„ ํ• ๋‹น ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ ์—ฐ๊ด€๋œ ๊ฐ์ฒด ๊ฒ€์ƒ‰ํ•˜๊ธฐ

Objective-C ๋Ÿฐํƒ€์ž„ ํ•จ์ˆ˜ objc_getAssociatedObject๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ด€๋œ ๊ฐ์ฒด๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ž์˜ ์˜ˆ์ œ๋ฅผ ๊ณ„์†ํ•ด์„œ, ๋‹ค์Œ ์ฝ”๋“œ ์ค„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์—์„œ overview๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

NSString *associatedObject =
    (NSString *)objc_getAssociatedObject(array, &overviewKey);

objc_getAssociatedObject: ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด์— ์—ฐ๊ด€๋œ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

๐Ÿ“Œ ์—ฐ๊ด€ ๊ด€๊ณ„ ๋Š๊ธฐ

์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๋Š์œผ๋ ค๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ’์œผ๋กœ nil์„ ์ „๋‹ฌํ•˜์—ฌ objc_setAssociatedObject๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค:

objc_setAssociatedObject(array, &overviewKey, nil, OBJC_ASSOCIATION_ASSIGN);

์—ฐ๊ด€๋œ ๊ฐ์ฒด๊ฐ€ nil๋กœ ์„ค์ •๋˜๋ฏ€๋กœ ์ •์ฑ…์€ ์‹ค์ œ๋กœ ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ฐ์ฒด์˜ ๋ชจ๋“  ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๋Š์œผ๋ ค๋ฉด objc_removeAssociatedObjects๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ฐ˜์ ์œผ๋กœ ์ด ํ•จ์ˆ˜๋Š” ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์˜ ๋ชจ๋“  ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ๋Š๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ฐ์ฒด๋ฅผ "์›์‹œ ์ƒํƒœ"๋กœ ๋ณต์›ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

objc_removeAssociatedObjects: ๊ฐ์ฒด์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

๐Ÿ“Œ ์ „์ฒด ์˜ˆ์ œ

๋‹ค์Œ ํ”„๋กœ๊ทธ๋žจ์€ ์•ž์˜ ์„น์…˜์˜ ์ฝ”๋“œ๋ฅผ ๊ฒฐํ•ฉํ•œ ์ „์ฒด ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
 
int main (int argc, const char * argv[]) {
 
    @autoreleasepool {
        static char overviewKey;
 
        NSArray *array = [[NSArray alloc]
            initWithObjects:@"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(array, &overviewKey);
        NSLog(@"associatedObject: %@", associatedObject);
 
        // ์—ฐ๊ด€ ๊ด€๊ณ„ ๋Š๊ธฐ
        objc_setAssociatedObject(
            array,
            &overviewKey,
            nil,
            OBJC_ASSOCIATION_ASSIGN
        );
        [array release];
    }
    return 0;
}

์—ฐ๊ด€ ์ฐธ์กฐ์˜ ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€

์—ฐ๊ด€ ์ฐธ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

  1. ์นดํ…Œ๊ณ ๋ฆฌ์— ํ”„๋กœํผํ‹ฐ ์ถ”๊ฐ€: Objective-C์˜ ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ๊ธฐ์กด ํด๋ž˜์Šค์— ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์—ฐ๊ด€ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ํ†ตํ•ด ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์„œ๋“œํŒŒํ‹ฐ ํด๋ž˜์Šค ํ™•์žฅ: ์†Œ์Šค ์ฝ”๋“œ์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํด๋ž˜์Šค์— ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ๋Ÿฐํƒ€์ž„ ๋ฐ์ดํ„ฐ ์บ์‹ฑ: ๊ฐ์ฒด์— ๊ด€๋ จ ๋ฐ์ดํ„ฐ๋ฅผ ์ž„์‹œ๋กœ ์ €์žฅํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  4. ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ์ฐธ์กฐ ๊ด€๋ฆฌ: ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํŒจํ„ด์„ ๊ตฌํ˜„ํ•  ๋•Œ ์•ฝํ•œ ์ฐธ์กฐ(weak reference)๋กœ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฃผ์˜์‚ฌํ•ญ

์—ฐ๊ด€ ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ช‡ ๊ฐ€์ง€ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ: ์ ์ ˆํ•œ ์—ฐ๊ด€ ์ •์ฑ…์„ ์„ ํƒํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋‚˜ ๋Œ•๊ธ€๋ง ํฌ์ธํ„ฐ๋ฅผ ๋ฐฉ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  2. ํ‚ค ์ถฉ๋Œ ๋ฐฉ์ง€: ๊ณ ์œ ํ•œ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ์ฝ”๋“œ์™€์˜ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  3. ์„ฑ๋Šฅ ๊ณ ๋ ค: ์—ฐ๊ด€ ์ฐธ์กฐ๋Š” ์ผ๋ฐ˜ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ณด๋‹ค ์•ฝ๊ฐ„ ๋А๋ฆด ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•œ ์ฝ”๋“œ์—์„œ๋Š” ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  4. ๋””๋ฒ„๊น… ์–ด๋ ค์›€: ์—ฐ๊ด€ ์ฐธ์กฐ๋Š” ์ฝ”๋“œ์—์„œ ๋ช…์‹œ์ ์œผ๋กœ ๋ณด์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋””๋ฒ„๊น…์ด ๋” ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ๋ฌด๋ฆฌ

Objective-C์˜ ์—ฐ๊ด€ ์ฐธ์กฐ๋Š” ํด๋ž˜์Šค ์ •์˜๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๊ฐ์ฒด์— ๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํŠนํžˆ ์„œ๋“œํŒŒํ‹ฐ ์ฝ”๋“œ๋ฅผ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ์นดํ…Œ๊ณ ๋ฆฌ์— ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.