Programming with Objective-C(4)

5248 단어 Objective-C
이번 주요 내용은 협의이다. 다른 고급 언어에서 우리는 보통 인터페이스가 있다. 주요 목적은 일련의 방법을 정의하여 특정한 종류를 실현시키기 위한 것이다. 그리고 이런 종류는 어느 정도의 공통성을 가지게 된다. 이때 우리는 다태적인 방식을 이용하여 인터페이스를 통해 이런 종류의 대상을 받아들일 수 있고 이런 대상이 도대체 어떤 종류에 속하는지 꺼리지 않는다.현재 인터페이스의 정의를 실현하는 방법만 알면 된다. 그리고 이 대상을 통해 우리는 이런 방법을 사용할 수 있다.
OC에서는 클래스가 직접 인터페이스로 인식되기 때문에 다른 언어와 인터페이스와 같은 기능을 실현하기 위해 애플이 프로토콜을 내놓았다.애플이 이를 프로토콜이라고 부르는 것은 애플이 보기에 우리가 코드를 작성할 때 특정한 상황에 부딪힐 수 있기 때문이다. 이러한 특정한 상황에 대해 우리는 특정한 처리 방식이 있고 이런 처리 방식은 특정한 제도에 따라 집행해야 하기 때문에 이런 제도를 프로토콜이라고 부른다.예를 들어, 우리가tableView를 사용할 때, 우리는tableView에 표시될 내용을 결정할 데이터 원본 대상이 필요하다. 그러면 어떤 내용을 표시해야 할지, tableView에서 메시지를 보내고 데이터 원본 대상에게 넘겨서 어떤 규칙에 따라 받아들여진 메시지에 따라 표시될 데이터를 결정해야 한다.
이 데이터 원본의 대상에 대해 사실 우리는 그것이 도대체 어떤 대상인지 신경 쓰지 않기 때문에, 우리는 보통 Table View Controller에 직접 맡겨 해결한다.실제로tableView에서도 마찬가지다. 데이터를 얻는 데 도움을 줄 대상이 어떤 대상일지 모르지만, 자신의 메시지를 받는 대상이 어떤 규칙을 따르고 데이터를 얻는 기능을 갖추고 있는지 확인하면 된다.
다음에 협의에 대해 정식으로 말하자면 협의의 정의는 매우 간단하다. 말하자면 협의는 우리로 하여금 일련의 방법과 속성을 정의하게 했다. 이런 속성과 방법은 모두 특정 클래스에 독립된 것이기 때문에 처음에 언급한 바와 같이 클래스의 공통성을 결정할 수 있다. 즉, 협의의 클래스가 이 협의에 첨부된 일련의 기능과 속성을 갖추는 것을 따른다.계약은 다음과 같이 선언됩니다.
@protocol ProtocolName
// List of methods and properties
@end

한 가지 주의해야 할 것은 앞에서 언급한 확장이나 유형과 다르다. 우선, 협의는 지원 방법과 속성이라는 점에서 유형과 구분된다.그 다음으로 협의는 클래스와 무관하다고 할 수 있다. 협의의 정의는 우리가 분석할 때 필요한 특정한 공공이 가지고 있는 행위와 관련이 있기 때문에 확장과 다르다. 이해할 때 협의를 클래스에 대한 확장이라고 볼 수 없다.
공식 문서에서 제시한 예에 따르면, 우리는 떡 모양의 그림으로 설명할 수 있다.하나의 떡그림에 대해 말하자면, 그것은 매우 많은 다른 블록을 포함할 수 있으며, 그 다음에 각 블록이 차지하는 공간은 모두 다를 수 있다.그러면 디자인을 할 때 우리는 이 보기의 중용성을 고려해야 한다. 여기서 우리의 보기는 두 가지 기능이 있다. 첫째, 데이터를 받아들일 수 있어야 한다. 데이터를 받아들일 수 없기 때문이다. 그러면 이 떡그림은 죽은 그림이다.두 번째는 데이터를 보여줄 수 있어야 한다는 것이다.만약에 이렇게 본다면 우리는 사실 일부 속성을 정의하고 몇 가지 방법을 더하면 이런 기능을 실현할 수 있다. 그러나 이렇게 하면 우리의 보기가 적재하는 기능이 약간 불필요해진다. 현재 많이 사용하는 디자인 모델이 바로 MVC이다. 특히 애플의 관련 개발에서 MVC는 어디에나 있다고 할 수 있다.MVC의 정수는 보기, 데이터 원본, 컨트롤러를 분리하는 데 있다. 이 세 가지가 섞이면 우리가 쓴 클래스가 매우 방대하고 코드가 혼란스럽기 쉽기 때문이다.따라서 MVC의 사상에 따르면 우리의 보기는 표시만 책임지면 된다. 구체적인 데이터의 획득은 다른 대상에게 맡기고 이 대상은 반드시 일정한 규칙에 따라 실현해야 한다. 우리가 앞서 언급한 데이터를 고려하면 이 협의는 이렇게 쓸 수 있다.
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegements;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end

다음에 우리의 떡그림에서 반드시 하나의 속성이 해당하는 데이터를 거슬러 올라갈 수 있어야 한다. 이 속성이 도대체 어느 대상을 가리키는지에 대해 우리는 관심이 없기 때문에 id 유형을 직접 사용한다. 다음과 같다.
@interface XYZPieChartView : UIView
@property (weak) id <XYZPieChartViewDataSource> dataSource;
...
@end

앞서 말한 바와 같이 우리는 데이터 소스가 도대체 어떤 대상인지에 관심이 없다. 우리가 유일하게 신경 써야 할 것은 그것이 협의에 따라 우리가 필요로 하는 기능을 실현할 수 있는지이다.
여기에 어떤 협의에 복종하는 대상을 어떻게 성명하는지에 관한 문제도 있다. OC에서 우리는 직접 뾰족한 괄호를 사용하고 그 중에서 협의 이름을 쓰면 된다. 이것은 이 대상이 상응하는 협의를 실현한 대상이라는 것을 증명한다.다음에 만약에 우리가 프로토콜을 실현하지 못한 대상에게 이 속성을 부여한다면 컴파일러는 우리에게 경고할 것이다. 따라서 우리가 필요로 하는 것은 어떤 프로토콜을 실현한 대상이라고 성명하면 컴파일 단계에서 우리는 이 대상이 도대체 구체적인 프로토콜을 실현했는지 확인할 수 있다. 이후에 문제가 생길까 봐 걱정할 필요가 없다.
협의에 관해서 또 한 가지 말하자면, 그것은 협의 중의 방법이다. 우리는 반드시 전부 실현해야 하는 것이 아니라, 우리는 선택할 수 있는 방법을 성명할 수 있다. 이런 방법들이 실현되는지 안 되는지는 결코 중요하지 않다.기본적으로, 우리가 성명하는 방법은 모두 필수적이다. 즉, 실현되지 않으면 컴파일러가 오류를 보고할 것이다. 선택할 수 있는 방법을 성명하려면 다음과 같이 할 수 있다.
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end;

@optional 뒤에 따라가는 것은 선택할 수 있는 방법입니다. 실제로 필요한 방법은 @required 뒤에 따라가야 하지만, 기본적으로 우리는 쓸 필요가 없습니다.
기왕 우리가 선택할 수 있는 방법이 생겼으니 문제도 생겼다. 운행할 때 우리는 어떻게 선택할 수 있는 방법을 호출해야 하는가?선택할 수 있는 방법이 반드시 실현된 것은 아니기 때문에 직접 호출하는 것은 안전하지 않다. 우리는 이 방법이 이미 실현되었는지 확인하고 다시 사용해야 한다. 확보할 때respondsToSelector:@selector() 방법을 사용할 수 있다. 다음과 같다.
NSString *thisSegmentTitle;
if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
    this.segmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}

프로토콜에 복종한 id 형식의 대상을respondToSelector 방법으로 호출하려고 하면 컴파일러가 오류를 보고하고 해당하는 실례적인 방법을 찾지 못했다는 것을 알립니다.하나의 프로토콜로 id 형식을 수식하면 모든 정적 형식 검사가 되돌아오고 특정한 프로토콜에 명시되지 않은 방법을 호출하면 오류가 발생합니다.이런 상황을 피하려면 NSObjects 프로토콜을 사용자 정의로 계승할 수 있습니다.
위에서 말한 바와 같이 우리가 프로토콜을 정의할 때 가장 좋은 선택은 바로 우리가 사용자 정의한 프로토콜로 NSObject 프로토콜을 계승하는 것이다. 주요 원인은 NSObject 클래스의 일부 행위가 NSObject 프로토콜에서 분리되기 때문이다. 따라서 만약에 우리의 프로토콜이 NSObject 프로토콜을 계승하지 않았다면 NSObject 클래스에 대응하는 많은 방법을 우리는 호출할 수 없을 것이다.계약의 상속은 다음과 같이 간단합니다.
@protocol MyProtocol <NSObject>
...
@end

마지막으로 한 종류를 성명할 때 이 종류가 상응하는 협의에 부합한다는 것을 어떻게 설명하는지에 관한 것이다. 사실 형식은 매우 간단하다. 다음과 같다.
@interface MyClass : NSObject <MyProtocol>
...
@end

또한 OC의 협의는 여러 개에 복종할 수 있으며 쉼표로 구분하면 된다.
애플의 말에 따르면, 만약 당신의 어떤 종류가 대량의 협의에 복종했다면, 이것은 당신의 종류가 약간 불필요하다는 것을 설명할 수 있을 것이다. 그것을 몇 개의 작은 종류로 나누어야 한다.비교적 자주 사용하는 방식 중 하나는 delegate를 사용하여 프로그램의 주요 기능을 포함하는 것이다.
공식 문서에서 한 가지 언급된 것은 협의의 사용이다. 앞서 언급한 것들을 제외하고는 클래스로 숨길 수 있다.간단하게 말하면 구체적으로 실현된 클래스는 우리가 다른 사람에게 보이고 싶지 않기 때문에 사용할 때 우리는 직접 이 클래스를 통해 대상을 얻지 않고 다른 클래스에 맡겨 대상을 만든다.획득할 때, 우리는 획득한 대상이 상응하는 방법을 가지고 있는지 확인하기만 하면 된다. 마치 아래의 코드와 같다
id <XYZFrameworkUtility> utility = [frameworkObject anonymousUtility];

기본적으로 협의의 용법에 관해서는 대개 이렇다. 개인적인 이해가 깊지 않으니 여러분의 지적을 환영합니다.

좋은 웹페이지 즐겨찾기