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

Obj-C ๊ณต์‹ ๋ฌธ์„œ ์ •๋ฆฌ - Categories์™€ Extensions

by BreadDev 2025. 4. 14.
728x90

์•ˆ๋…•ํ•˜์„ธ์š”. ์˜ค๋Š˜์€ Objective-C์˜ Categories์™€ Extensions์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ๋“ค์€ ๊ธฐ์กด ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜๋Š” ์œ ์šฉํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ Categories์™€ Extensions ๊ฐœ์š”

Category๋Š” ๊ธฐ์กด ํด๋ž˜์Šค์— ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์‹ฌ์ง€์–ด ์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ํด๋ž˜์Šค์—๋„ ์ ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค! Categories๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋ธŒํด๋ž˜์‹ฑ ์—†์ด๋„ ๊ธฐ์กด ํด๋ž˜์Šค์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ž์‹ ์˜ ํด๋ž˜์Šค ๊ตฌํ˜„์„ ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๋ถ„์‚ฐ์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Class Extensions(ํ™•์žฅ)์€ Categories์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์ฃผ ํด๋ž˜์Šค์˜ @interface ๋ธ”๋ก ์™ธ๋ถ€์—์„œ ํด๋ž˜์Šค์— ํ•„์š”ํ•œ ์ถ”๊ฐ€ API๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

Category: ๊ธฐ์กด ํด๋ž˜์Šค์— ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” Objective-C์˜ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
Extension: ์ต๋ช… ์นดํ…Œ๊ณ ๋ฆฌ์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์„ ์–ธ๋œ ๋ฉ”์„œ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ ํ•ด๋‹น ํด๋ž˜์Šค์˜ ๋ฉ”์ธ ๊ตฌํ˜„๋ถ€์—์„œ ๊ตฌํ˜„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ ํด๋ž˜์Šค์— ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€ํ•˜๊ธฐ

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

#import "ClassName.h"
 
@interface ClassName (CategoryName)
// ๋ฉ”์„œ๋“œ ์„ ์–ธ
@end

์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์€ ์ด ๋ฉ”์„œ๋“œ๋“ค์ด ๋‹ค๋ฅธ ๊ณณ์—์„œ ์„ ์–ธ๋œ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ถ”๊ฐ€์ž„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ž˜์Šค์— ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

์ค‘์š”: ์นดํ…Œ๊ณ ๋ฆฌ๋Š” ๋ฉ”์„œ๋“œ๋งŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋™์ž‘ ๋ฐฉ์‹

์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋Š” ํด๋ž˜์Šค ํƒ€์ž…์˜ ์ผ๋ถ€๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์นดํ…Œ๊ณ ๋ฆฌ์—์„œ NSArray ํด๋ž˜์Šค์— ์ถ”๊ฐ€๋œ ๋ฉ”์„œ๋“œ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ NSArray ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๋Š” ๋ฉ”์„œ๋“œ ๋ชฉ๋ก์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

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

// NSString+Utils.h
@interface NSString (Utils)
- (BOOL)isEmpty;
@end

// NSString+Utils.m
@implementation NSString (Utils)
- (BOOL)isEmpty {
    return self.length == 0;
}
@end

์œ„ ์˜ˆ์ œ์—์„œ๋Š” NSString ํด๋ž˜์Šค์— isEmpty๋ผ๋Š” ์ƒˆ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์นดํ…Œ๊ณ ๋ฆฌ์™€ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜ ๋ฒ”์œ„

์นดํ…Œ๊ณ ๋ฆฌ๋Š” ํด๋ž˜์Šค์— ์ถ”๊ฐ€ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํด๋ž˜์Šค ๋ฒ”์œ„ ๋‚ด์˜ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋ฒ”์œ„ ๋‚ด์—๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” @private์œผ๋กœ ์„ ์–ธ๋œ ๋ณ€์ˆ˜๋ฅผ ํฌํ•จํ•˜์—ฌ ํด๋ž˜์Šค๊ฐ€ ์„ ์–ธํ•œ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ์ˆ˜์—๋Š” ์ œํ•œ์ด ์—†์ง€๋งŒ, ๊ฐ ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„์€ ๋‹ฌ๋ผ์•ผ ํ•˜๋ฉฐ, ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ ์„ธํŠธ๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ Extensions(ํ™•์žฅ)

Class Extensions๋Š” ์ต๋ช… ์นดํ…Œ๊ณ ๋ฆฌ์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์„ ์–ธ๋œ ๋ฉ”์„œ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ ํ•ด๋‹น ํด๋ž˜์Šค์˜ ๋ฉ”์ธ @implementation ๋ธ”๋ก์—์„œ ๊ตฌํ˜„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Clang/LLVM 2.0 ์ปดํŒŒ์ผ๋Ÿฌ ์ด์ƒ์„ ์‚ฌ์šฉํ•˜๋ฉด ํด๋ž˜์Šค ํ™•์žฅ์—์„œ ํ”„๋กœํผํ‹ฐ์™€ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@interface MyClass : NSObject
@property (retain, readonly) float value;
@end
 
// ๋น„๊ณต๊ฐœ ํ™•์žฅ, ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฉ”์ธ ๊ตฌํ˜„ ํŒŒ์ผ์— ์ˆจ๊ฒจ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค.
@interface MyClass ()
@property (retain, readwrite) float value;
@end

ํด๋ž˜์Šค ํ™•์žฅ์˜ ํŠน์ง•: ์นดํ…Œ๊ณ ๋ฆฌ์™€ ๋‹ฌ๋ฆฌ ๋‘ ๋ฒˆ์งธ @interface ๋ธ”๋ก์˜ ๊ด„ํ˜ธ ์•ˆ์— ์ด๋ฆ„์ด ์ง€์ •๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ™•์žฅ์˜ ์ผ๋ฐ˜์ ์ธ ์šฉ๋„

ํด๋ž˜์Šค ํ™•์žฅ์˜ ์ผ๋ฐ˜์ ์ธ ์šฉ๋„๋Š” ๊ณต๊ฐœ์ ์œผ๋กœ ์ฝ๊ธฐ ์ „์šฉ(readonly)์œผ๋กœ ์„ ์–ธ๋œ ํ”„๋กœํผํ‹ฐ๋ฅผ ๋น„๊ณต๊ฐœ์ ์œผ๋กœ ์ฝ๊ธฐ-์“ฐ๊ธฐ(readwrite)๋กœ ์žฌ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ๋Š” ๊ฐ’์„ ์ฝ์„ ์ˆ˜๋งŒ ์žˆ์ง€๋งŒ, ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ๋Š” ๊ฐ’์„ ๋ณ€๊ฒฝํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

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

@interface MyClass : NSObject
- (float)value;
@end
 
 
@interface MyClass () {
    float value;
}
- (void)setValue:(float)newValue;
@end
 
@implementation MyClass
 
- (float)value {
    return value;
}
 
- (void)setValue:(float)newValue {
    value = newValue;
}
 
@end

์ด ์˜ˆ์ œ์—์„œ setValue: ๋ฉ”์„œ๋“œ์˜ ๊ตฌํ˜„์€ ํด๋ž˜์Šค์˜ ๋ฉ”์ธ @implementation ๋ธ”๋ก ๋‚ด์— ๋‚˜ํƒ€๋‚˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๋Š” setValue: ๋ฉ”์„œ๋“œ์˜ ์ •์˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒฝ๊ณ ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๐Ÿ“Œ ์นดํ…Œ๊ณ ๋ฆฌ์™€ ํ™•์žฅ์˜ ์‹ค์šฉ์  ์‚ฌ์šฉ ์˜ˆ

์นดํ…Œ๊ณ ๋ฆฌ ์‚ฌ์šฉ ์˜ˆ

  1. ๊ธฐ๋Šฅ ๊ทธ๋ฃนํ™”: ํฐ ํด๋ž˜์Šค์˜ ๊ด€๋ จ ๋ฉ”์„œ๋“œ๋ฅผ ๋…ผ๋ฆฌ์  ๊ทธ๋ฃน์œผ๋กœ ๋ถ„ํ• 
     
    @interface UIView (Animation)
    // ์• ๋‹ˆ๋ฉ”์ด์…˜ ๊ด€๋ จ ๋ฉ”์„œ๋“œ
    @end
    
    @interface UIView (Layout)
    // ๋ ˆ์ด์•„์›ƒ ๊ด€๋ จ ๋ฉ”์„œ๋“œ
    @end
  2. ์™ธ๋ถ€ ํ”„๋ ˆ์ž„์›Œํฌ ํ™•์žฅ: ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํด๋ž˜์Šค์— ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
     
    @interface NSString (URLEncoding)
    - (NSString *)urlEncodedString;
    @end
  3. ํ”„๋กœํ† ์ฝœ ๊ตฌํ˜„ ๋ถ„๋ฆฌ: ํ”„๋กœํ† ์ฝœ ๊ตฌํ˜„์„ ๋ณ„๋„์˜ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ
     
    @interface MyViewController (UITableViewDataSource) <UITableViewDataSource>
    // UITableViewDataSource ํ”„๋กœํ† ์ฝœ ๋ฉ”์„œ๋“œ
    @end

ํ™•์žฅ ์‚ฌ์šฉ ์˜ˆ

  1. ๋น„๊ณต๊ฐœ ๋ฉ”์„œ๋“œ ์ •์˜: ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ ์„ ์–ธ
     
    @interface MyClass ()
    - (void)privateHelperMethod;
    @end
  2. ์ฝ๊ธฐ ์ „์šฉ ํ”„๋กœํผํ‹ฐ์˜ ๋น„๊ณต๊ฐœ ์ˆ˜์ •:
     
    // ๊ณต๊ฐœ ์ธํ„ฐํŽ˜์ด์Šค
    @interface Account : NSObject
    @property (nonatomic, readonly) double balance;
    @end
    
    // ๋น„๊ณต๊ฐœ ํ™•์žฅ
    @interface Account ()
    @property (nonatomic, readwrite) double balance;
    @end

๋งˆ๋ฌด๋ฆฌ

Categories์™€ Extensions๋Š” ๊ธฐ์กด ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ๋” ๋ชจ๋“ˆํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋ธŒํด๋ž˜์‹ฑ ์—†์ด๋„ ๊ธฐ์กด ํด๋ž˜์Šค์— ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํ™•์žฅ์€ ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๋” ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.