Objective-C 둘러보기(4)

jonghwan·2022년 10월 12일
0

멋쟁이사자처럼

목록 보기
26/28
post-thumbnail

동적 바인딩(Dynamic Binding)

동적 바인딩은 컴파일 시간이 아닌 런타임에 호출할 메서드를 결정합니다.

동적 바인딩은 후기 바인딩이라고도 합니다.

Objective-C에서 모든 메소드는 런타임에 동적으로 해결됩니다.

실행되는 정확한 코드는 메소드 이름(선택자)과 수신 객체에 의해 결정됩니다.

동적 바인딩은 다형성을 가능하게 합니다.

예를 들어, Rectangle 및 Square를 포함한 개체 컬렉션을 고려하십시오.

각 개체에는 고유한 printArea 메서드 구현이 있습니다.

다음 코드에서 [anObject printArea] 표현식에 의해 실행되어야 하는 실제 코드는 런타임에 결정됩니다.

런타임 시스템은 메서드 실행을 위한 선택기를 사용하여 Object의 클래스가 무엇이든 적절한 메서드를 식별합니다.

#import <Foundation/Foundation.h>

@interface Square:NSObject {
 float area;
}

- (void)calculateAreaOfSide:(CGFloat)side;
- (void)printArea;
@end

@implementation Square
- (void)calculateAreaOfSide:(CGFloat)side {
 area = side * side;
}

- (void)printArea {
 NSLog(@"The area of square is %f",area);
}
@end

@interface Rectangle:NSObject {
 float area;
}

- (void)calculateAreaOfLength:(CGFloat)length andBreadth:
(CGFloat)breadth;
- (void)printArea;
@end

@implementation Rectangle

- (void)calculateAreaOfLength:(CGFloat)length andBreadth:
(CGFloat)breadth {
 area = length * breadth;
}

- (void)printArea {
 NSLog(@"The area of Rectangle is %f",area);
}
@end

int main() {
 Square *square = [[Square alloc]init];
 [square calculateAreaOfSide:10.0];

 Rectangle *rectangle = [[Rectangle alloc]init];
 [rectangle calculateAreaOfLength:10.0 andBreadth:5.0];

 NSArray *shapes = [[NSArray alloc]initWithObjects: square, rectangle,nil];
 id object1 = [shapes objectAtIndex:0];
 [object1 printArea];

 id object2 = [shapes objectAtIndex:1];
 [object2 printArea];

 return 0;
}

// The area of square is 100.000000
// The area of Rectangle is 50.000000

위의 예에서 볼 수 있듯이 printArea 메서드는 런타임에 동적으로 선택됩니다.

이는 동적 바인딩의 예이며 유사한 종류의 개체를 처리할 때 많은 상황에서 매우 유용합니다.

복합 객체(Composite Objects)

클래스 클러스터 내에 객체를 포함하는 클래스를 정의하는 하위 클래스를 생성할 수 있습니다.

이러한 클래스 개체는 복합 객체입니다.

따라서 클래스 클러스터가 무엇인지 궁금할 수 있습니다. 따라서 먼저 클래스 클러스터가 무엇인지 살펴보겠습니다.

클래스 클러스터(Class Clusters)

클래스 클러스터는 Foundation 프레임워크에서 광범위하게 사용하는 디자인 패턴입니다.

클래스 클러스터는 공개 추상 수퍼클래스 아래에 여러 개인 구체적인 하위 클래스를 그룹화합니다.

이러한 방식으로 클래스를 그룹화하면 기능적 풍부함을 줄이지 않으면서 객체 지향 프레임워크의 공개적으로 보이는 아키텍처를 단순화할 수 있습니다.

클래스 클러스터는 Abstract Factory 디자인 패턴을 기반으로 합니다.

간단하게 하기 위해 유사한 기능에 대해 여러 클래스를 만드는 대신 입력 값을 기반으로 처리를 처리하는 단일 클래스를 만듭니다.

예를 들어 NSNumber에는 char, int, bool 등과 같은 클래스 클러스터가 많이 있습니다.

단일 클래스에서 유사한 작업을 처리하는 단일 클래스로 모든 것을 그룹화합니다.

NSNumber는 실제로 이러한 기본 유형의 값을 개체로 래핑합니다.

그렇다면 복합 객체란 정확히 무엇일까요?(What is a Composite Object?)

자체 설계한 개체에 개인 클러스터 개체를 포함하여 복합 개체를 만듭니다.

이 복합 개체는 기본 기능을 위해 클러스터 개체에 의존할 수 있으며 복합 개체가 특정 방식으로 처리하려는 메시지만 가로채게 됩니다.

이 아키텍처는 작성해야 하는 코드의 양을 줄이고 Foundation Framework에서 제공하는 테스트된 코드를 활용할 수 있도록 합니다.

복합 개체는 클러스터의 추상 슈퍼클래스의 하위 클래스로 자신을 선언해야 합니다.

하위 클래스로서 상위 클래스의 기본 메서드를 재정의해야 합니다.

파생 메서드를 재정의할 수도 있지만 파생 메서드는 기본 메서드를 통해 작동하기 때문에 필요하지 않습니다.

NSArray 클래스의 count 메소드가 한 예입니다. 재정의하는 메서드의 중간 개체 구현은 다음과 같이 간단할 수 있습니다.

예에서 포함된 객체는 실제로 NSArray 유형입니다.

 (unsigned)count {
 return [embeddedObject count];
}

복합 객체 예제(A Composite Object Example)

#import <Foundation/Foundation.h>

@interface ValidatingArray : NSMutableArray {
 NSMutableArray *embeddedArray;
}

+ validatingArray;
- init;
- (unsigned)count;
- objectAtIndex:(unsigned)index;
- (void)addObject:object;
- (void)replaceObjectAtIndex:(unsigned)index withObject:object;
- (void)removeLastObject;
- (void)insertObject:object atIndex:(unsigned)index;
- (void)removeObjectAtIndex:(unsigned)index;

@end

@implementation ValidatingArray
- init {
 self = [super init];
 if (self) {
 embeddedArray = [[NSMutableArray allocWithZone:[self zone]] init];
 }
 return self;
}

+ validatingArray {
 return [[self alloc] init] ;
}

- (unsigned)count {
 return [embeddedArray count];
}

- objectAtIndex:(unsigned)index {
 return [embeddedArray objectAtIndex:index];
}

- (void)addObject:(id)object {
 if (object != nil) {
 [embeddedArray addObject:object];
 }
}

- (void)replaceObjectAtIndex:(unsigned)index withObject:(id)object; {
 if (index <[embeddedArray count] && object != nil) {
 [embeddedArray replaceObjectAtIndex:index withObject:object];
 }
}

- (void)removeLastObject; {
 if ([embeddedArray count] > 0) {
 [embeddedArray removeLastObject];
 }
}

- (void)insertObject:(id)object atIndex:(unsigned)index; {
 if (object != nil) {
 [embeddedArray insertObject:object atIndex:index];
 }
}

- (void)removeObjectAtIndex:(unsigned)index; {
 if (index <[embeddedArray count]) {
 [embeddedArray removeObjectAtIndex:index];
 }
}
@end

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 ValidatingArray *validatingArray = [ValidatingArray validatingArray];

 [validatingArray addObject:@"Object1"];
 [validatingArray addObject:@"Object2"];
 [validatingArray addObject:[NSNull null]];
 [validatingArray removeObjectAtIndex:2];
 NSString *aString = [validatingArray objectAtIndex:1];
 NSLog(@"The value at Index 1 is %@",aString);
 [pool drain];

 return 0;
}

// The value at Index 1 is Object2

앞의 예에서 배열의 하나의 기능을 검증하면 정상적인 시나리오에서 충돌을 일으킬 null 개체를 추가할 수 없음을 알 수 있습니다.

그러나 우리의 검증 배열이 그것을 처리합니다.

마찬가지로 배열 유효성 검사의 각 방법은 일반적인 작업 순서와 별도로 유효성 검사 프로세스를 추가합니다.

Foundation Framework

Apple 문서를 참조하면 아래와 같이 Foundation 프레임워크의 내용을 확인할 수 있습니다.

Foundation 프레임워크는 Objective-C 클래스의 기본 계층을 정의합니다. 유용한 기본 객체 클래스 세트를 제공하는 것 외에도 Objective-C 언어에서 다루지 않는 기능을 정의하는 여러 패러다임을 소개합니다. 프레임워크는 이러한 목표를 염두에 두고 설계되었습니다.

  • 작은 기본 유틸리티 클래스 세트를 제공합니다.

  • 할당 해제와 같은 일관된 규칙을 도입하여 소프트웨어 개발을 더 쉽게 만듭니다.

  • 유니코드 문자열, 개체 지속성 및 개체 배포를 지원합니다.

  • 이식성 향상을 위해 OS 독립성 수준을 제공합니다.

프레임워크는 Apple이 인수한 NeXTStep에서 개발했으며 이러한 기초 클래스는 Mac OS X 및 iOS의 일부가 되었습니다.

NeXTStep에 의해 개발되었기 때문에 클래스 접두사 "NS"가 있습니다.

우리는 모든 샘플 프로그램에서 Foundation Framework를 사용했습니다. Foundation Framework를 사용하는 것은 거의 필수입니다.

일반적으로 #import <Foundation/NSString.h> 와 같은 것을 사용 하여 Objective-C 클래스를 가져오지만 너무 많은 클래스를 가져오는 것을 방지하기 위해 모두 #import <Foundation/Foundation.h> 에서 가져옵니다.

NSObject는 기초 키트 클래스를 포함한 모든 개체의 기본 클래스입니다.

메모리 관리 방법을 제공합니다.

또한 런타임 시스템에 대한 기본 인터페이스와 Objective-C 개체로 동작하는 기능을 제공합니다.

기본 클래스가 없으며 모든 클래스의 루트입니다.

기능별 Foundation의 클래스들(Foundation Classes based on functionality)

데이터 저장소(Data storage)

데이터 저장 및 검색은 모든 프로그램에서 가장 중요한 것 중 하나입니다.

Objective-C에서는 일반적으로 작업을 복잡하게 만들기 때문에 연결 목록과 같은 구조에 의존하지 않습니다.

대신 NSArray, NSSet, NSDictionary 및 변경 가능한 형식과 같은 컬렉션을 사용합니다.

NSArray와 NSMutableArray(Data storage)

NSArray는 변경할 수 없는 객체 배열을 유지하는 데 사용되며 NSMutableArray는 변경 가능한 개체 배열을 유지하는 데 사용됩니다.

가변성은 런타임에 미리 할당된 배열을 변경하는 데 도움이 되지만 NSArray를 사용하는 경우 기존 배열만 교체하고 기존 배열의 내용은 변경할 수 없습니다.

NSArray의 중요한 메소드는 다음과 같습니다.

  • alloc/initWithObjects - 객체로 배열을 초기화하는 데 사용됩니다.
  • objectAtIndex - 특정 인덱스에 있는 개체를 반환합니다.
  • count - 객체의 수를 반환합니다.

NSMutableArray는 NSArray에서 상속되므로 NSArray의 모든 인스턴스 메서드는 NSMutableArray에서 사용할 수 있습니다.

NSMutableArray의 중요한 메소드는 다음과 같습니다.

  • removeAllObjects - 배열을 비웁니다.

  • addObject - 배열의 끝에 주어진 객체를 삽입합니다.

  • removeObjectAtIndex - 특정 인덱스에서 objectA를 제거하는 데 사용됩니다.

  • exchangeObjectAtIndex:withObjectAtIndex - 주어진 인덱스에서 배열의 개체를 교환합니다.

  • replaceObjectAtIndex:withObject - 인덱스의 개체를 개체로 바꿉니다.

#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 NSArray *array = [[NSArray alloc]
 initWithObjects:@"string1", @"string2",@"string3",nil];
 NSString *string1 = [array objectAtIndex:0];
 NSLog(@"The object in array at Index 0 is %@",string1);

 NSMutableArray *mutableArray = [[NSMutableArray alloc]init];
 [mutableArray addObject: @"string"];
 string1 = [mutableArray objectAtIndex:0];
 NSLog(@"The object in mutableArray at Index 0 is %@",string1);

 [pool drain];
 return 0;
}

// The object in array at Index 0 is string1
// The object in mutableArray at Index 0 is string

NSDictionary와 NSMutableDictionary(Data storage)

NSDictionary는 개체의 변경 불가능한 사전을 유지하는 데 사용되며 NSMutableDictionary는 개체의 변경 가능한 사전을 유지하는 데 사용됩니다.

NSDictionary의 중요한 메소드는 다음과 같습니다.

  • alloc/initWithObjectsAndKeys - 지정된 값 및 키 세트로 구성된 항목으로 새로 할당된 사전을 초기화합니다.

  • valueForKey - 주어진 키와 관련된 값을 반환합니다.

  • count - 사전의 항목 수를 반환합니다.

NSMutableDictionary는 NSDictionary에서 상속되므로 NSDictionary의 모든 인스턴스 메서드는 NSMutableDictionary에서 사용할 수 있습니다.

NSmutableDictionary의 중요한 메소드는 다음과 같습니다.

  • removeAllObjects - 항목의 사전을 비웁니다.

  • removeObjectForKey - 사전에서 주어진 키와 관련 값을 제거합니다.

  • setValue:forKey - 주어진 키-값 쌍을 사전에 추가합니다.

#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
 @"string1",@"key1", @"string2",@"key2",@"string3",@"key3",nil];
 NSString *string1 = [dictionary objectForKey:@"key1"];
 NSLog(@"The object for key, key1 in dictionary is %@",string1);

 NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc]init];
 [mutableDictionary setValue:@"string" forKey:@"key1"];
 string1 = [mutableDictionary objectForKey:@"key1"];
 NSLog(@"The object for key, key1 in mutableDictionary is %@",string1);

 [pool drain];
 return 0;
}

// The object for key, key1 in dictionary is string1
// The object for key, key1 in mutableDictionary is string

NSSet와 NSMutableSet(Data storage)

NSSet은 고유한 개체의 변경 불가능한 집합을 유지하는 데 사용되며 NSMutableDictionary는 고유한 개체의 변경 가능한 집합을 유지하는 데 사용됩니다.

NSSet의 중요한 메소드는 다음과 같습니다.

  • alloc/initWithObjects - 지정된 개체 목록에서 가져온 구성원으로 새로 할당된 집합을 초기화합니다.

  • allObjects - 집합의 구성원을 포함하는 배열을 반환하거나 집합에 구성원이 없는 경우 빈 배열을 반환합니다.

  • count - 집합의 구성원 수를 반환합니다.

NSMutableSet은 NSSet에서 상속되므로 NSSet의 모든 인스턴스 메서드는 NSMutableSet에서 사용할 수 있습니다.

NSMutableSet의 중요한 메소드는 다음과 같습니다.

  • removeAllObjects - 모든 구성원 집합을 비웁니다.

  • addObject - 이미 구성원이 아닌 경우 지정된 개체를 집합에 추가합니다.

  • removeObject - 세트에서 주어진 객체를 제거합니다.

#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 NSSet *set = [[NSSet alloc]
 initWithObjects:@"string1", @"string2",@"string3",nil];
 NSArray *setArray = [set allObjects];
 NSLog(@"The objects in set are %@",setArray);

 NSMutableSet *mutableSet = [[NSMutableSet alloc]init];
 [mutableSet addObject:@"string1"];
 setArray = [mutableSet allObjects];
 NSLog(@"The objects in mutableSet are %@",setArray);

 [pool drain];
 return 0;
}

// The objects in set are (string3, string2, string1)
// The objects in mutableSet are (string1)

텍스트와 문자열(Text and strings)

NSString은 문자열과 텍스트를 저장하는 데 사용되는 가장 일반적으로 사용되는 클래스 중 하나입니다.

NSString에 대해 더 알고 싶다면 Objective-C strings에서 NSString을 참조하세요.

앞서 언급했듯이 NSCharacterSet은 NSString 및 NSScanner 클래스에서 사용되는 다양한 문자 그룹을 나타냅니다.

NSCharacterSet(Text and strings)

다음은 다양한 문자 집합을 나타내는 NSCharacterSet에서 사용할 수 있는 메서드 집합입니다.

  • alphanumericCharacterSet - 문자, 표시 및 숫자 범주의 문자를 포함하는 문자 집합을 반환합니다.

  • CapitalizedLetterCharacterSet - Titlecase Letters 범주의 문자를 포함하는 문자 집합을 반환합니다.

  • characterSetWithCharactersInString - 주어진 문자열의 문자를 포함하는 문자 세트를 반환합니다.

  • characterSetWithRange - 주어진 범위에서 유니코드 값을 가진 문자를 포함하는 문자 세트를 반환합니다.

  • 불법 문자 집합 - 비문자 범주의 값을 포함하거나 유니코드 표준 버전 3.2에서 아직 정의되지 않은 문자 집합을 반환합니다.

  • letterCharacterSet - 문자 및 표시 범주의 문자를 포함하는 문자 집합을 반환합니다.

  • lowercaseLetterCharacterSet - 소문자 범주의 문자를 포함하는 문자 세트를 반환합니다.

  • newlineCharacterSet - 개행 문자를 포함하는 문자 세트를 반환합니다.

  • punctuationCharacterSet - 구두점 카테고리의 문자를 포함하는 문자 세트를 반환합니다.

  • symbolCharacterSet - 기호 범주의 문자를 포함하는 문자 세트를 반환합니다.

  • uppercaseLetterCharacterSet - 대문자 및 제목 대문자 범주의 문자를 포함하는 문자 세트를 반환합니다.

  • whitespaceAndNewlineCharacterSet - 유니코드 일반 범주 Z*, U000A ~ U000D 및 U0085를 포함하는 문자 집합을 반환합니다.

  • whitespaceCharacterSet - 인라인 공백 문자 공백(U+0020)과 탭(U+0009)만 포함하는 문자 세트를 반환합니다.

#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
 NSString *string = @"....Tutorials Point.com…..";
 NSLog(@"Initial String :%@", string);
 
 NSCharacterSet *characterset = [NSCharacterSet punctuationCharacterSet];
 string = [string stringByTrimmingCharactersInSet:characterset];
 NSLog(@"Final String :%@", string);

 [pool drain];
 return 0;
}

// Initial String :....Tutorials Point.com.....
// Final String :Tutorials Point.com

날짜와 시간(Dates and times)

NSDate 및 NSDateFormatter 클래스는 날짜 및 시간 기능을 제공합니다.

NSDateFormatter는 NSDate를 NSString으로 또는 그 반대로 쉽게 변환할 수 있는 도우미 클래스입니다.

다음은 NSDate를 NSString으로 변환하고 다시 NSDate로 변환하는 간단한 예입니다.

#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 NSDate *date= [NSDate date];
 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
 [dateFormatter setDateFormat:@“yyyy-MM-dd"];
 
 NSString *dateString = [dateFormatter stringFromDate:date];
 NSLog(@"Current date is %@“,dateString);
 NSDate *newDate = [dateFormatter dateFromString:dateString];
 NSLog(@"NewDate: %@",newDate);
 [pool drain];
 return 0;
}

// Current date is 2013-09-29
// NewDate: 2013-09-28 18:30:00 +0000

예제 프로그램에서 볼 수 있듯이 NSDate의 도움으로 현재 시간을 얻습니다.

NSDateFormatter는 형식 변환을 처리하는 클래스입니다.

날짜 형식은 사용 가능한 데이터에 따라 변경될 수 있습니다.

예를 들어 위의 예에 시간을 추가하려는 경우 날짜 형식을 @"yyyy-MM-dd:hh:mm:ss"로 변경할 수 있습니다.

예외 처리(Exception handling)

예외 처리는 기본 클래스 NSException이 있는 Objective-C에서 사용할 수 있습니다.

예외 처리는 다음 블록으로 구현됩니다.

  • @try - 이 블록은 일련의 명령문을 실행하려고 시도합니다.

  • @catch - 이 블록은 try 블록에서 예외를 잡으려고 시도합니다.

  • @finally - 이 블록에는 항상 실행되는 일련의 명령문이 포함되어 있습니다.

다음의 예제는 예외로 인해 프로그램이 종료되는 대신 예외 처리를 사용했기 때문에 계속 진행됩니다.

#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
 NSMutableArray *array = [[NSMutableArray alloc]init];
 
 @try {
 NSString *string = [array objectAtIndex:10];
 } @catch (NSException *exception) {
 NSLog(@"%@ “,exception.name);
 NSLog(@"Reason: %@ “,exception.reason)
 }
 
@finally {
 NSLog(@"@@finaly Always Executes”);
 }
 
 [pool drain];
 return 0;
}

// NSRangeException
// Reason: *** -[__NSArrayM objectAtIndex:]: index 10 beyond bounds for empty array
// @finally Always Executes

파일 처리(File handling)

NSFileManager 클래스의 도움으로 파일 처리를 사용할 수 있습니다. 이 예제는 온라인 컴파일러에서 작동하지 않습니다.

파일 처리에 사용되는 방법

파일 액세스 및 조작 에 사용되는 방법 목록 은 다음과 같습니다. 여기에서 원하는 작업을 수행하려면 FilePath1, FilePath2 및 FilePath 문자열을 필요한 전체 파일 경로로 바꿔야 합니다.

파일이 경로에 존재하는지 확인

NSFileManager *fileManager = [NSFileManager defaultManager];

//Get documents directory
NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [directoryPaths objectAtIndex:0];

if ([fileManager fileExistsAtPath:@""] == YES) {
 NSLog(@"File exists");
} 

두 파일 내용 비교

if ([fileManager contentsEqualAtPath:@"FilePath1" andPath:@" FilePath2"]) {
 NSLog(@"Same content");
}

쓰기 가능, 읽기 가능, 실행 가능 여부 확인

if ([fileManager isWritableFileAtPath:@"FilePath"]) {
 NSLog(@"isWritable");
}

if ([fileManager isReadableFileAtPath:@"FilePath"]) {
 NSLog(@"isReadable");
}

if ( [fileManager isExecutableFileAtPath:@"FilePath"]) {
 NSLog(@"is Executable");
}

파일 이동

if([fileManager moveItemAtPath:@"FilePath1" toPath:@"FilePath2" error:NULL]) {
 NSLog(@"Moved successfully”);
}

파일 복사

if ([fileManager copyItemAtPath:@“FilePath1" toPath:@"FilePath2" error:NULL]) {
 NSLog(@"Copied successfully");
}

파일 삭제

if ([fileManager removeItemAtPath:@"FilePath" error:NULL]) {
 NSLog(@"Removed successfully");
}

파일 읽기

NSData *data = [fileManager contentsAtPath:@"Path"];

파일 쓰기

[fileManager createFileAtPath:@"" contents:data attributes:nil];

URL 로딩 시스템(URL loading system)

URL 로딩은 URL, 즉 인터넷에서 항목에 액세스하는 데 유용합니다. 다음 클래스의 도움으로 제공됩니다.

  • NSMutableURL요청

  • NSURL연결

  • NSURL캐시

  • NSURL인증 챌린지

  • NSURL자격 증명

  • NSURLProtectionSpace

  • NSURL응답

  • NSURL다운로드

  • NSURL세션

URL 로딩에 대한 예제는 코코아 애플리케이션 프로젝트에서 가능합니다. (생략)

빠른 열거(Fast Enumeration)

빠른 열거는 컬렉션을 열거하는 데 도움이 되는 Objective-C의 기능입니다.

따라서 빠른 열거에 대해 알기 위해서는 앞서 살펴본 Foundation Framework에서 제공하는 컬렉션에 대해 먼저 알아야 합니다.

컬렉션(Collections)

컬렉션에는 여러 가지 유형이 있습니다. 그것들은 모두 다른 개체를 보유할 수 있다는 동일한 목적을 수행하지만, 대부분 개체를 검색하는 방식이 다릅니다.

Objective-C에서 사용되는 가장 일반적인 컬렉션은 다음과 같습니다.

  • NSSet

  • NSArray

  • NSDictionary

  • NSMutableSet

  • NSMutableArray

  • NSMutableDictionary

빠른 열거 구문(Fast enumeration Syntax)

for (classType variable in collectionObject ) {
 statements
}
#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 NSArray *array = [[NSArray alloc]
 initWithObjects:@"string1", @"string2",@"string3",nil];

 for(NSString *aString in array) {
 NSLog(@"Value: %@",aString);
 }

 [pool drain];
 return 0;
}

// Value: string1
// Value: string2
// Value: string3

뒤로 빠른 열거(Fast Enumeration Backwards)

for (classType variable in [collectionObject reverseObjectEnumerator] ) {
 statements
}
#import <Foundation/Foundation.h>

int main() {
 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 NSArray *array = [[NSArray alloc]
 initWithObjects:@"string1", @"string2",@"string3",nil];

 for(NSString *aString in [array reverseObjectEnumerator]) {
 NSLog(@"Value: %@",aString);
 }

 [pool drain];
 return 0;
}

// Value: string3
// Value: string2
// Value: string1

메모리 관리(Memory Management)

메모리 관리는 모든 프로그래밍 언어에서 가장 중요한 프로세스 중 하나입니다.

객체의 메모리가 필요할 때 할당되고 더 이상 필요하지 않을 때 할당 해제되는 프로세스입니다.

개체 메모리 관리는 성능 문제입니다.

응용 프로그램이 불필요한 개체를 해제하지 않으면 메모리 사용 공간이 늘어나고 성능이 저하됩니다.

Objective-C 메모리 관리 기술은 크게 두 가지 유형으로 분류할 수 있습니다.

  • "수동 유지 해제" 또는 MRR
  • "자동 참조 카운팅" 또는 ARC

"수동 유지 해제" 또는 MRR("Manual Retain-Release" or MRR)

MRR에서는 자체적으로 개체를 추적하여 메모리를 명시적으로 관리합니다.

이것은 Foundation 클래스 NSObject가 런타임 환경과 함께 제공하는 참조 카운팅으로 알려진 모델을 사용하여 구현됩니다.

MRR과 ARC의 유일한 차이점은 전자에서는 유지 및 해제가 수동으로 처리되고 후자는 자동으로 처리된다는 것입니다.

다음 그림은 Objective-C에서 메모리 관리가 작동하는 방식의 예를 나타냅니다.

  1. Class A 객체의 메모리 수명 주기는 위 그림과 같습니다. 보시다시피, 유지 횟수는 개체 아래에 표시되며 개체의 유지 횟수가 0이 되면 개체가 완전히 해제되고 다른 개체가 사용할 수 있도록 메모리가 할당 해제됩니다.

  2. 클래스 A 객체는 먼저 NSObject에서 사용 가능한 alloc/init 메소드를 사용하여 생성됩니다. 이제 유지 횟수가 1이 됩니다.

  3. 이제 클래스 B는 클래스 A의 객체를 유지하고 클래스 A의 객체의 보유 횟수는 2가 됩니다.

  4. 그런 다음 클래스 C는 개체의 복사본을 만듭니다. 이제 인스턴스 변수에 대해 동일한 값을 사용하여 클래스 A의 다른 인스턴스로 생성됩니다. 여기서 유지 횟수는 1이며 원본 개체의 유지 횟수가 아닙니다. 이것은 그림에서 점선으로 표시됩니다.

  5. 복사된 객체는 릴리스 메소드를 사용하여 클래스 C에 의해 해제되고 보유 횟수가 0이 되므로 객체가 파괴됩니다.

  6. 초기 Class A Object의 경우 유지 횟수는 2이며 두 번 해제해야 소멸됩니다. 이것은 보유 횟수를 각각 1과 0으로 감소시키는 클래스 A와 클래스 B의 릴리스 문에 의해 수행됩니다. 마지막으로 개체가 파괴됩니다.

우리는 우리가 생성한 모든 객체를 소유합니다.

  • 이름이 "alloc", "new", "copy" 또는 "mutableCopy"로 시작하는 메서드를 사용하여 객체를 생성합니다.

유지를 사용하여 객체의 소유권을 얻을 수 있습니다.

수신된 객체는 일반적으로 수신된 메서드 내에서 유효한 상태로 유지되며 해당 메서드는 객체를 호출자에게 안전하게 반환할 수도 있습니다.

우리는 두 가지 상황에서 유지를 사용합니다.

  • 접근자 메서드 또는 초기화 메서드의 구현에서 속성 값으로 저장하려는 개체의 소유권을 가져옵니다.

  • 다른 작업의 부작용으로 개체가 무효화되는 것을 방지합니다.

더 이상 필요하지 않을 때 우리는 우리가 소유한 객체의 소유권을 포기해야 합니다.

객체에 릴리스 메시지 또는 자동 릴리스 메시지를 전송하여 객체의 소유권을 포기합니다.

따라서 Cocoa 용어에서 객체의 소유권을 포기하는 것을 일반적으로 객체 "릴리스"라고 합니다.

소유하지 않은 개체의 소유권을 포기해서는 안 됩니다.

이는 명시적으로 명시된 이전 정책 규칙의 결과일 뿐입니다.

"수동 유지 해제" 또는 MRR("Manual Retain-Release" or MRR)

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
 NSLog(@"Hello, World! \n");
}

- (void)dealloc {
 NSLog(@"Object deallocated");
 [super dealloc];
}

@end

int main() {

 /* my first program in Objective-C */
 SampleClass *sampleClass = [[SampleClass alloc]init];
 [sampleClass sampleMethod];

 NSLog(@"Retain Count after initial allocation: %d",
 [sampleClass retainCount]);
 [sampleClass retain];

 NSLog(@"Retain Count after retain: %d", [sampleClass retainCount]);
 [sampleClass release];
 NSLog(@"Retain Count after release: %d", [sampleClass retainCount]);
 [sampleClass release];
 NSLog(@"SampleClass dealloc will be called before this");

 // Should set the object to nil
 sampleClass = nil;
 return 0;
}

/*
Hello, World!
Retain Count after initial allocation: 1
Retain Count after retain: 2
Retain Count after release: 1
Object deallocated
SampleClass dealloc will be called before this
*/

"자동 참조 카운팅" 또는 ARC("Automatic Reference Counting" or ARC)

자동 참조 카운팅 또는 ARC에서 시스템은 MRR과 동일한 참조 카운팅 시스템을 사용하지만 컴파일 타임에 적절한 메모리 관리 방법 호출을 삽입합니다.

우리는 새로운 프로젝트에 ARC를 사용할 것을 강력히 권장합니다.

ARC를 사용하는 경우 일반적으로 이 문서에 설명된 기본 구현을 이해할 필요가 없지만 일부 상황에서는 도움이 될 수 있습니다.

ARC에 대한 자세한 내용은 Apple의 ARC 릴리스 노트를 참조하세요.

위에서 언급했듯이 ARC에서는 컴파일러에서 처리하므로 릴리스 및 유지 메서드를 추가할 필요가 없습니다.

실제로 Objective-C의 기본 프로세스는 여전히 동일합니다.

내부적으로 유지 및 해제 작업을 사용하여 개발자가 이러한 작업에 대해 걱정하지 않고 더 쉽게 코딩할 수 있으므로 작성된 코드의 양과 메모리 누수 가능성이 모두 줄어듭니다.

Mac OS-X에서 MRR과 함께 사용하는 가비지 수집이라는 또 다른 원칙이 있었지만 OS-X Mountain Lion에서 폐지된 이후로 MRR의 대안이 되지 못하고 사라졌습니다.

또한 iOS 개체에는 가비지 수집 기능이 없었습니다.

그리고 ARC를 사용하면 OS-X에서도 가비지 수집을 사용하지 않습니다.

다음은 간단한 ARC 예제입니다.

이것은 ARC를 지원하지 않기 때문에 온라인 컴파일러에서는 작동하지 않습니다.

#import <Foundation/Foundation.h>

@interface SampleClass:NSObject
- (void)sampleMethod;
@end

@implementation SampleClass
- (void)sampleMethod {
 NSLog(@"Hello, World! \n");
}

- (void)dealloc {
 NSLog(@"Object deallocated");
}

@end

int main() {
 /* my first program in Objective-C */
 @autoreleasepool {
 SampleClass *sampleClass = [[SampleClass alloc]init];
 [sampleClass sampleMethod];
 sampleClass = nil;
 }
 return 0;
}

// Hello, World!
// Object deallocated

0개의 댓글