Effective Objective-C 2.0 독서노트 2 (상)
제2장 대상, 메시지, 운행기
OC는 대상을 대상으로 하는 언어로'대상'은 그 중에서 가장 중요한 것이다. 우리는 대상 유형을 통해 데이터와 데이터 전달을 저장하고 대상과 메시지 전달을 잘 이해하면 프로그램 작성에 큰 도움이 될 것이다.
6. "속성"이라는 개념 이해
여러분은 속성에 대해 어느 정도 인식을 가지고 있다고 믿습니다. 군말은 하지 않겠습니다. 다음은 여러분이 개의치 않을 수 있는 부분만 말씀드리겠습니다.
@interface aViewController :UIViewController{
UIView *_aView;
}
@property UIView *aView;
@end
에 있습니다.m 파일 중
@synthesize aView = _aView;
나중에 이렇게 쓰는 것이 매우 힘들다는 것을 알게 되었고 한 걸음 한 걸음 개선을 거쳐 컴파일러에게 어떤 일을 맡겼다. 그래서 나중에 이렇게 쓰기만 하면
@interface aViewController :UIViewController
@property UIView *aView;
@end
이렇게 쓰면 컴파일러가 자동으로 우리에게aView 실력 변수와 set, get 방법 주의점: 1.@interface만 @property가 없으면 정의된 실력 변수는self를 사용할 수 없습니다.self 때문에 호출되었습니다.실제적으로 set이나 get 방법을 호출하고 @property를 쓰지 않으면 set과 get 방법을 자동으로 생성하지 않습니다 (self. = 오른쪽에서 set 방법을 호출하고 = 왼쪽에서 get 방법을 호출합니다.)2. 아직 있다면.m중사
@synthesize
,에 해당하는aView가 또 이름을 지었다.3. 현재 애플은 @property만 쓰는 것을 추천합니다.4. 컴파일러가 자동으로 set과 get 방법을 생성하지 않으려면 우리는 할 수 있다.m에 다음과 같은 문을 추가합니다.@dynamic aView;
5. 범주의 속성은 다음과 같은 인스턴스 변수를 생성하지 않습니다.
@interface UIViewController (UINavigationControllerItem)
@property(nonatomic,readonly,strong) UINavigationItem *navigationItem;
@property(nonatomic) BOOL hidesBottomBarWhenPushed;
@property(nullable, nonatomic,readonly,strong) UINavigationController *navigationController;
@end
위의 세 속성에는 대응하는 실례 변수가 없다.우리는 속성의 위치를 정의하는 데 주의해야 한다. 일반적으로 노출될 속성만 정의한다.h에서, 그리고 일반적으로 바깥에 노출된 속성은 모두 자독이고 실현 방법에서 자신이 사용하는 속성은 일반적으로 정의된다.m의 분류 중.7. 능숙한 사용자 정의 set, get 방법, 게으름 피우기 등 형식 숙련
@property (nonatomic, strong) UIView *aView;
속성에는 네 가지 특징이 있는데 그것이 바로 원자성, 읽기와 쓰기 권한, 메모리 관리의 의미, 방법명이다. 구체적인 각 특징은 상세하게 소개하지 않고 무시할 수 있는 세부 사항만 말한다.원자성은 보통nonatomic을 사용하는데 만약에 우리가 atomic을 사용하면 iOS의 동기화 자물쇠를 호출하고 메모리 비용이 비교적 크며 Mac OS 프로그램을 개발할 때 atomic를 사용하는 것이 비교적 많다.2. 메모리 관리의 의미는 컴파일러의 합성 접근 방법을 결정하고 신중하게 선택한다. 특히 우리가 set, get 방법을 사용자 정의할 때, 예를 들어 우리가 하나의 속성의 특질이copy라고 성명할 때, 우리는 사용자 정의set 방법을 사용할 때 반드시 대상을 복사해야 한다. 그렇지 않으면 사용자를 오도하여 BUG가 생길 수 있다.3. 방법명은 접근 방법의 방법명을 지정할 수 있지만 일반적으로 거의 사용하지 않는다
setter=
.다른 방법에서도 속성 값을 설정하려면 클래스를 사용자 정의하고 초기화 방법을 사용자 정의하는 등 속성 정의의 특성을 준수해야 합니다.@interface aPeopleClass : NSObject
@property(copy) NSString *firstName;
@property(copy) NSString *lastName;
-(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName;
@end
이 사용자 정의 초기화 방법을 실현할 때 반드시'copy'의 의미를 따라야 한다. 초기화 방법은 이렇게 쓸 수 있다.
-(id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName{
if (self = [super init]){
_firstName = [firstName copy];
_lastName = [lastName copy];
}
}
주의: init와 dealloc에서self를 사용해서는 안 됩니다.set이나 get 방법을 사용합니다. 또한 하나의 속성의 이러한 특징을 잘 쓰면 이 속성을 쉽게 이해하고 개발을 더욱 간단하게 할 수 있습니다.
7. 대상 내부에서 실력 변수를 직접 방문해야 한다
대상의 외부 방문 실례 변수는 항상 속성을 통과하지만 내부 방문 실력 변수를 사용할 때 어떤 방법을 써야 할지 항상 논쟁을 벌이고 있다. 책에서 실력 변수를 읽을 때 직접 방문하는 형식으로 실력 변수를 설정할 때 속성을 통해 하는 것이 권장된다.두 가지 방법의 차이점: 1.직접 접근 속도는 속성 접근보다 빠르다. 메모리에 직접 접근하기 때문에 방법을 거치지 않는다.2. 직접 액세스는 키 값 관측(KVO)을 트리거하지 않습니다.3. 속성 접근을 통해 문제를 조사하는 데 도움이 됩니다. 왜냐하면 설정 방법에 단점을 추가할 수 있기 때문입니다.주의해야 할 점: 1.앞에서 언급한 바와 같이 초기화 방법에서 항상 실례 변수에 직접 접근해야 한다. 왜냐하면 하위 클래스는 설정 방법을 복제할 수 있기 때문이다. (때때로 우리는 초기화 방법에서 속성 접근을 사용해야 할 수도 있다. 예를 들어 초기화되어야 하는 실력 변수는 하위 클래스에서 설명한 것이다.)2. 우리가'타성 초기화'를 사용할 때 반드시 설정 방법을 통해 속성에 접근해야 한다. 그렇지 않으면 실력 변수는 영원히 초기화되지 않는다('타성 초기화'의 장점은 메모리를 절약하는 것이다).
8.'대상 등동성'이라는 개념 이해
등동성은 서로 같다. 우리는 코드를 작성할 때 자주 사용된다.우선 강조해야 할 점은
==
를 대상이 같은 판단으로 사용할 수 없다는 것이다. ==
는 지침 자체를 비교하는 것이지 지침이 가리키는 대상이 아니기 때문이다.우리가 자주 사용하는 비교적 같은 방법은 다음과 같다.객체 유형
메서드
NSString
isEqualToString:
NSArray
isEqualToArray:
NSDictionary
isEqualToDictionary:
NSSet
isEqualToSet:
NSObject 프로토콜에는 동일성을 판단하는 두 가지 중요한 방법이 있습니다(이 두 가지 방법은 동일성 방법을 사용자 정의할 때 유용합니다).
- (BOOL)isEqual:(id)object;
- (NSUInteger)hash;
아래
isEqualToString:
와 isEqual:
의 차이는 isEqual:
가 먼저 대상 유형을 판단한 다음에 대상 중의 구체적인 세부 사항이 같은지 판단하는 것이다.또한 isEqual:
로 두 대상이 같다는 조건을 판단하면 두 대상이 같다면 그hash방법은 반드시 하나의 값으로 되돌아와야 한다. 반대로hash값이 같은 두 대상isEqual:
방법은 반드시 둘이 같다고 생각하지 않는다.다음은 특정 클래스 판단 등 동성의 예를 들어 간단한 클래스를 먼저 작성한다.@interface EOCPerson : NSObject
@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, copy) NSString *lastName;
@property (nonatomic, assign) NSUInteger age;
@end
그리고 등동성 방법을 사용자 정의합니다.
- (BOOL)isEqualToPerson:(EOCPerson*)otherPerson {
if (self == object) return YES;
if (![_firstName isEqualToString:otherPerson.firstName])
return NO;
if (![_lastName isEqualToString:otherPerson.lastName])
return NO;
if (_age != otherPerson.age)
return NO;
return YES;
}
- (BOOL)isEqual:(id)object {
if ([self class] == [object class]) {
return [self isEqualToPerson:(EOCPerson*)object];
} else {
return [super isEqual:object];
}
}
- (NSUInteger)hash {
NSUInteger firstNameHash = [_firstName hash];
NSUInteger lastNameHash = [_lastName hash];
NSUInteger ageHash = _age;
return firstNameHash ^ lastNameHash ^ ageHash;
}
등동성을 판단하는 것이 자주 필요하다면 자신이 만든 등동성 판단 방법은 검측 속도를 높일 수 있고, 이렇게 쓴 코드는 더욱 이해하기 쉽다.위의 코드에서 해시 코드의 생성 알고리즘은 추천한 것으로 이런 알고리즘은 효율적이고 생성된 해시 코드의 충돌률이 낮다.자신이 등동성 판정 방법을 쓸 때 하등동성 판정의 집행 깊이를 주의해야 한다. 무섭게 들리지만 실제는 매우 간단하다. 바로 우리가 등동성을 판정하는 기준과 판정 절차이다. 예를 들어 위의 사용자 정의 방법은 먼저 같은 유형인지 아닌지를 판정한 다음에 안의 속성이 같은지 판정한다. 이렇게 등급이 있는 판정은 우리 코드의 효율을 높일 수 있다. 또한,사용자 정의 판정 기준은 우리 스스로 결정하고 우리 스스로 어떤 기준에 도달할지 결정하는 것이 우리 개발에 더욱 유리하다.컨테이너에 있는 가변 클래스의 등동성은 주로 컨테이너에 가변 클래스를 넣어서 발생하는 문제이다. 이 문제는 우리가 하나의 기준을 준수하는 것이 바로 해시 코드를 생성할 때 클래스의 불가변 부분에 따라 생성해야 한다는 것이다. 예를 들어 설명하자(우리는 가변 집합에 몇 개의 가변 그룹을 추가해야 한다).
NSMutableSet *aSet = [NSMutableSet new];
NSMutableArray *arrayA = [@[@1, @2] mutableCopy];
[aSet addObject:arrayA];
이 때 집합에arrayA와 같은 그룹을 추가하려면 집합의 특성 때문에 (집합에 중복된 요소가 없습니다)
NSMutableArray *arrayB = [@[@1, @2] mutableCopy];
[aSet addObject:arrayB];
성공하지 못할 것입니다. 이 때 우리는 다른 방법으로 가변 수조arrayC를 작성한 다음arrayC를arrayA와 같은 수조로 바꿉니다.
NSMutableArray *arrayC = [@[@1] mutableCopy];
[aSet addObject:arrayC];
//
[arrayC addObject:@2];
이때 우리는 집합 중에 뜻밖에도 두 개의 같은 수조가 있다는 것을 발견하였다.그러나 우리가 이 집합을 복사할 때 집합 중의 수조가 또 하나로 변했다. 이런 결과는 우리가 보고 싶지 않은 것이다.
9.'클래스 모드'로 디테일 숨기기
많은 사람들이 유족을 들어본 적이 있고 매일 유족을 사용하지만 이 점을 의식하지 못했을 수도 있고 자신도 써 본 적이 없을 수도 있다. 사실 이런 상황을 초래한 원인은 매우 많다. 첫째, 유족의 표현 형식이 뚜렷하지 않아서 우리는 개의치 않을 수도 있다. 둘째, 우리는 프로그램을 쓸 때 미리 계획을 세우지 않고 전체적인 것을 세우지 못했기 때문에 유족이라는 것을 고려하지 않을 것이다.유족을 설명하자면 각 유족은 하나의 기류와 일부 자류를 가지고 있다. 기류는 기본적인 기능과 속성을 정의했고 자류는 이 기류에 계승된 것이다. 그러나 각 자류는 각기 다른 형태를 가진다. 이런 기류가 정의한 기능과 속성은 자류가 자기 내부에서 실현된 것이고 인터페이스는 기류가 노출된 것이다. 그래서 우리가 기류 인터페이스를 호출할 때 자류가 구체적으로 어떻게 실현되었는지 전혀 모른다.모든 하위 클래스의 독특한 기능만 알면 된다. 클래스족은 하나의 현저한 특징을 가지고 있다. 바로 베이스 방법을 호출하여 되돌아오는 실례가 베이스의 실례가 아니라 하위 클래스의 실례이다. 이해하기 어려울 수도 있다. 코드와 결합: 하나의 베이스를 정의한다.
typedef NS_ENUM(NSInteger, EOCEmployeeType){
EOCEmployeeTypeDeveloper,
EOCEmployeeTypeDesigner,
EOCEmployeeTypeFinance,
}; //
@interface EOCEmployee : NSObject
//
@property (copy) NSString *name;
@property NSUInteger salary;
//
+ (EOCEmployee *)employeeWithType:(EOCEmployeeType)type;
- (void)doADayWork;
@end
기본 클래스의 구현:
@implementation EOCEmployee
+ (EOCEmployee *)employeeWithType:(EOCEmployeeType)type{
switch (type) {
case EOCEmployeeTypeDeveloper:
return [EOCEmployeeTypeDeveloper new];
break;
case EOCEmployeeTypeDesigner:
return [EOCEmployeeTypeDesigner new];
break;
case EOCEmployeeTypeFinance:
return [EOCEmployeeTypeFinance new];
break;
default:
break;
}
//
}
- (void)doADayWork{
//
}
@end
하위 클래스 중 하나를 정의합니다.
@interface EOCEmployeeTypeDeveloper : EOCEmployee
@end
하위 클래스의 구현:
@implementation EOCEmployeeTypeDeveloper
- (void)doADayWork{
//
}
@end
위쪽은 사용자 정의 클래스의 예이다. 사실 우리가 사용하는 시스템 프레임워크에는 많은 클래스가 있다. 예를 들어 UIButton을 만드는 클래스 방법 등이 있다.
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
자신이 유족을 잘 쓰려면 좋은 예를 찾아서 많이 모방하고 많이 연습해야 한다.기존 유족에 실체 자류를 늘리는 데 있어서 우리는 반드시 아래의 원칙을 따라야 한다.자류는 반드시 유족 중의 기류를 계승해야 한다.2. 자류는 자신의 데이터 저장 방법을 정의해야 한다. 이 점은 가장 중요하고 무시하기 쉽다. (우리는 부류가 우리를 도와 데이터를 저장하기를 기대할 수 없다. 부류 자체는 케이스일 뿐 실례가 없기 때문이다).3. 자류가 부류 중에서 반드시 복사해야 하는 방법.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.