#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface CandleModel : NSObject{
UIImage *imageCandleOn;
UIImage *imageCandleOff;
BOOL nowStatus;
}
- (UIImage *) imageCandleOn;
- (void) setImageCandleOn:(UIImage *)newImage;
- (UIImage *) imageCandleOff;
- (void) setImageCandleOff:(UIImage *)newImage;
- (BOOL) nowStatus;
- (void) setNowStatus:(BOOL)newStatus;
- (NSString *) stringNowStatus;
@end
#import "CandleModel.h"
@implementation CandleModel
//id면 컴파일 할 때 알 수 있는데(리턴 후에 값이 받아드려질 때)
//instancetype이면 캔들모델이구나 하고 인식을 할 수 있음
- (instancetype) init{
self = [super init];
if (self){
imageCandleOn = [UIImage imageNamed:@"candle on.jpg"];
imageCandleOff = [UIImage imageNamed:@"candle off.jpg"];
_strong UIImage *temp = [[UIImage alloc] init];
//temp를 강하게 잡고 있음. if 문이 끝나면 사라지니까 내부적으로 인타임 모듈이 보내버려서 사라져버림.
_weak UIImage *tempweak = temp;
//temp 사라지면 다 사라짐
}
return self;
}
//ARC 사용하고 있어 컴파일러가 알아서 다 해줌 그래서 dealloc 안 씀..
//그래서 init이라는 생성자만 있고 소멸자를 안써줌
// - (void) deaaloc{
// [super dealloc];
// }
@end
strong & weak 예시 코드
@interface CandleModel(){
_weak UIImage *tempWeak;
}
@end
@implementation CandleModel
- (instancetype) init{
self = [super init];
if (self){
imageCandleOn = [UIImage imageNamed:@"candle on.jpg"];
imageCandleOff = [UIImage imageNamed:@"candle off.jpg"];
_strong UIImage *temp = [[UIImage alloc] init];
tempWeak = temp;
NSLog(@"%@", tempWeak);
//이미지 객체의 주소가 찍히겠지. 지역변수 안에서 strong하게 잡고 있는 temp를 가리키고 있으니까
}
NSLog(@"%@", tempWeak);
//근데 If 문 구간 벗어나면 temp가 pop된다. 그럼 if문 바깥의 tempWeak는 nil값이 들어옴
return self;
}
@end
header에 대해서 getter, setter 를 구현하는 코드 (m파일 implement 뒤에 추가)
- (UIImage *) imageCandleOn{
return imageCandleOn;
}
- (void) setImageCandleOn:(UIImage *)newImage{
imageCandleOn = newImage;
}
- (UIImage *) imageCandleOff{
return imageCandleOff;
}
- (void) setImageCandleOff:(UIImage *)newImage{
imageCandleOff = newImage;
}
- (BOOL) nowStatus{
return nowStatus;
}
- (void) setNowStatus:(BOOL)newStatus{
nowStatus = newStatus;
}
- (NSString *) stringNowStatus{
NSString *rValue = nil;
if (nowStatus == FALSE){
rValue = @"Candle is Off..";
}
else{
rValue = @"Candle is On!!";
}
return rValue;
}
이제 기존에 있었던 App delegate 와 연결해서 붕어빵을 찍어보자!
#import <UIKit/UIKit.h>
@class CandleModel;
@interface AppDelegate : UIResponder <UIApplicationDelegate> {
IBOutlet UIImageView *viewImage;
IBOutlet UILabel *labelStatus;
IBOutlet UISwitch *switchNow;
CandleModel *modelCandle;
}
@property (strong, nonatomic) IBOutlet UIWindow *window;
- (IBAction)touchSwitch:(id)sender;
@end
모델을 사용할 때 import를 보통 사용하지만 헤더의 사이즈도 줄이고 import가 중복포함도 막아주지만, 중복포함 없이 객체를 좀 더 명확하게 물리적으로 분리하기 위해서 @class 라고 선언한다.
@class (앳 클래스) : 캔들 모델에 클래스의 정의는 우리 프로젝트의 어딘가에 정의 되어 있으니까(somewhere), 컴파일 시에 있다고 퉁치고 넘어가자. 그럼 언제 실질적으로 여기에 대한 자료형을 지정하느냐! , 런타임 모듈상에서 모델 캔들의 객체가 레퍼런스 되었을 때 그때 명시하자. (캔들 모델의 존재함을 나타냄 )
AppDelegate.m
#import "CandleModel.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
modelCandle = [[CandleModel alloc] init];//캔들모델 인스턴스 생성
}
property :
클래스의 멤버변수들에 대해서 property로 재선언할 수 있다. 그럼 property는 property 내부의 또다른 속성인 attribute에 의해서 getter, setter가 자동으로 선언된다.
CandleModel.h
- (UIImage *) imageCandleOn;
- (void) setImageCandleOn:(UIImage *)newImage;
//위를 프로퍼티로 선언하면 아래 코드가 됨!!!
@property (nonatomic, strong) UIImage *imageCandleOn; //getter, setter가 자동으로 선언
- (BOOL) nowStatus;
- (void) setNowStatus:(BOOL)newStatus;
//위 아래 같은 의미
@property (nonatomic, assign) BOOL nowStatus; // bool은 스칼라 값이라 assign
//직접생성
- (UIImage *) imageCandleOn{
return imageCandleOn;
}
- (void) setImageCandleOn:(UIImage *)newImage{
imageCandleOn = newImage;
}
//위에 구현 코드를 안쓰고 synthesize로 선언만 해주면 된다. 같은 의미임.
@synthesize imageCandleOn; //getter, setter의 상태에 따라 자동으로 구현 가능
그래서 위에 코드들이 어떻게 바뀌냐면
@interface CandleModel : NSObject{
UIImage *imageCandleOn;
UIImage *imageCandleOff;
BOOL nowStatus;
}
- (UIImage *) imageCandleOn;
- (void) setImageCandleOn:(UIImage *)newImage;
@end
↓👇
@interface CandleModel : NSObject
@property (nonatomic, strong) UIImage *imageCandleOn;
@end
@implementation CandleModel
- (instancetype) init{
self = [super init];
if (self){
_imageCandleOn = [UIImage imageNamed:@"candle on.jpg"]; //언더바 추가
_imageCandleOff = [UIImage imageNamed:@"candle off.jpg"];
}
}
@end
그런데..! 굳이 내가 _가 붙은 이름을 쓰고 싶지 않아 🤔 → 이럴 때 @synthesize 를 사용해용
@synthesize imageCandleOn = qwerty; //그럼 멤버변수의 이름에 대해서 내부적으로는 qwerty 써줘
@interface CadleModel : NSObject{ UIImage *qwerty; }
복사하는 법
만약, b가 얕은 복사(shallow copy)를 했다면?
일단은 다른 객체를 갖는 것처럼 보임. 근데 a가 멤버변수를 수정하면 b도 바뀜.
이번에는 깊은 복사 (deep copy) 하면?
모든 걸 메모리 상에 완전히 다른 객체를 만들어버림.
assign : 단순할당 일 때는 하나의 객체를 인스턴스를 모두 같이 참조한다.
shallow copy : 최상단에 있는 애들만 일단 복사가 되고 내부의 멤버는 모두 공유한다.
deep copy : 아이덴티컬하게 아예 분리되서 복사된다.
[NSObject copyWithZone:(id)zone];
CandleModel.m
- (void) setImageCandleOff:(UIImage *)newImage{
_imageCandleOff = [newImage copy];
}
근데 UIImage 레퍼런스 들어가보면 NSCopying 만족을 안함. 그래서 nil 반환함. NSString은 만족함.
그래서 @property (nonatomic, copy) UIImage *imageCandleOff; 를 하면 setter가 구현이 된다.
getter , setter 이름 바꿔주고 싶어
@property (nonatomic, strong, getter=hahaha, setter=hohoho:) UIImage *imageCandleOff;
readwrite : 기본적인 옵션, getter , setter 모두 다 만들어줌
readonly : 그냥 참조만 하세요.
nonatomic : setter가 코딩이 된다.
atomic : 멤버 접근에 대해서 뮤택스가 설정이 된다. 단일 스레드를 구현할 때는 의미가 없어서 보통 nonatomic 씀.