Objective-C

알파관·2022년 10월 9일
0
post-thumbnail

2022.10.06

Swift의 조상님(?)인 Objective0-C 언어를 부트캠프에서 배워보게되었다.

앞으로 자주 쓸 언어는 아니지만, 그래도 iOS 개발로 진출을 한다면 가끔씩 마주칠 수도 있는 언어이기에 집중해서 공부를 해보도록 하겠다..!


📌 개요

- 역사 및 특징

Object-C 언어는 1980년대 초 브래드 콕스가 설계한 언어이며, 아래의 특징을 가진다.

SmallTalk-80 언어 기반

C언어 위에 있는 계층정(layered) 구조

C언어를 확장하여 '객체'를 생성하고 다룰 수 있는 새 언어

Objective-C는 캡슐화, 데이터 은닉, 계승, 다형성 등의 특징을 지니는 객체 지향 언어이다.

1988년에 NeXT Software는 Objective-C언어로 NeXTSTEP 운영체제 개발환경과 라이브러리를 개발하였고, NeXT는 추후에 애플에 인수된다.

그렇게 NeXT가 인수되면서 Mac OS X와 iPhone OS 앱 개발의 기본언어는 자연스레 Objective-C가 되었다.

하지만, 시대가 변하면서 Objective-C언어의 불편함에 많은 iOS 개발자들이 힘들어했으며 새로운 언어 등장 붐이 일면서 애플도 Swift라는 언어를 개발했다.

애플이 iOS 개발 언어를 Swift로 바꾸기 시작하면서, Objective-C는 개발에서 더 이상 쓰이지 않는 일이 많아졌다.

실제로 Objective-C의 마지막 최신버전 발표는 2007년 이후 나오지 않고 있다.

대세에서는 밀렸으나 과거에 Objective-C로 만들었던 코드들이 남아있기도 하고, Swift도 결국엔 Objective-C를 바탕으로 만들어졌기에 여전히 Objective-C의 가치는 살아있다.


📌 프로그램 구조

Objective-C 프로그램은 기본적으로 다음 부분으로 구성된다.

  • 전처리기 명령

  • 인터페이스

  • 구현

  • 메소드

  • 변수

  • 진술 및 표현

  • 주석

"Hello World"를 출력하는 기본 예제코드를 살펴보면서 구조에 대해 정확히 파악해보자.

#import <Foundation/Foundation.h>

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

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

int main() {
	SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass sampleMethod];
    return 0;
}



1) 전처리기 명령

#import <Foundation/Foundation.h>

프로그램의 첫 번째 줄은 전처리기 명령부이다.
컴파일 되기 전에 처리해야할 명령을 넣는 부분이다.

본 코드에서는 컴파일러가 컴파일을 시작하기 전에 Foundation.h 파일을 포함하라고 지시한다.

2) 인터페이스 선언

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

Objective-C에서는 인터페이스란 것을 생성한다.
클래스를 선언하고, 그 안에서 쓰이는 메서드를 선언해준다.

@implementation - @end로 시작과 끝을 꼭 알려주어야하며, NSObject 클래스를 꼭 상속해줘야한다.

NSObject 클래스는 런타임 시스템에 대한 인터페이스 역할을 하는 '루트 클래스'이다.

또한, 메서드를 선언할 때 앞에 -, + 등을 붙인다.

앞에 -가 붙는 경우는 Swift에서 func 키워드를 이용한 일반적인 인스턴스 메서드를 선언하는 경우라고 생각하면된다.

그리고 +가 붙는 경우는 class func 키워드를 이용한 Swift에서의 타입 메서드를 선언하는 경우라고 생각하면 된다.

3) 구현

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

인터페이스 파트에서 선언한 클래스의 메서드를 구현해주는 부분이다.

@implementation - @end로 구현부의 시작과 끝을 꼭 표시해줘야한다.

내부 구현은 Objective-C 문법에 따라 코딩하면 된다.

4) main 함수

int main() {
	SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass sampleMethod];
    return 0;
}

Objective-C에서 main()은 프로그램이 실행되는 주요 함수이다.

이 부분도 구현부와 마찬가지로, Objective-C 문법에 따라 코드를 작성해주면 된다.

[[SampleClass alloc]init];은 클래스 인스턴스를 선언해주는 주요 코드

[samplecClass sampleMethod];는 인스턴스를 통해 메서드를 호출하는 주요 코드이다.


📌 데이터 타입

Objective-C의 타입은 다음과 같이 분류할 수 있다.

  • 기본 타입

    산술타입이며 정수 및 부동 소수점 타입으로 구성된다.

  • 열거형

    산술타입이며 프로그램 전체에서 특정 불연속 정수 값만 할당할 수 있는 변수를 정의

  • 타입 무효

    형식 지정자 void는 사용할 수 있는 값이 없음을 나타냄
  • 파생 타입

    포인터 타입, 배열 타입, 구조 타입, 통합 타입 및 함수 타입이 포함됨

Swift 타입과의 주된 타입이라고 한다면 Int, Double이 기본 타입이라는 것이다.

Swift에서의 Int, Double은 구조체에 해당하기 때문이다.


- 기본 타입

  • 정수타입(Integer Types)

    아래 표는 저장 크기와 값 범위가 있는 표준 정수 타입에 대한 세부 정보를 제공한다.

    저장 크기와 종류는 Swift와 유사하다.

    한가지 유의할 점이라면, Objective-C에서의 char은 1 byte 크기의 유니코드가 아닌 '아스키코드'를 말한다.

  • 부동소수점 타입(Floating-Point Types)

    아래 표는 저장 크기와 값 범위 및 정밀도가 있는 표준 부동 소수점 타입에 대한 세부 정부를 제공한다.

    이 또한, 저장 크기와 종류가 Swift와 유사하다.


- 열거형

Swift와 마찬가지로 enum 키워드를 활용하여 열거형을 정의한다.

enum month {
	january = 1, february, march, april, 
    may, june, july, august, september, october, 
    november, december
};

위 코드는 month라는 열거형 타입을 선언한 코드이다.

이렇게 선언한 타입으로 변수를 만들어서 해당 열거형 타입 내의 값들에 접근할 수 있게 된다.

열거형 타입의 변수를 정의하는 방법은 아래와 같다.

enum month vars, wars;
vars = january;
wars = december;

정의된 변수에는 열거형 내에 선언된 값들 (january, february....)만 들어올 수 있다.

#import <Foundation/Foundation.h>


int main(int argc, const char * argv[])
{

	enum month { january = 1, february, march, april, may, june, july, august, september, october, november, december };
    
	enum month amonth;         
    int days;
    
	NSLog (@"Enter month number: "); 
	scanf ("%i", &amonth);
	
	switch (amonth) { 
    	case january:
		case march: 
        case may:
		case july:
		case august: 
		case october: 
		case december:
			days = 31;
			break; 
		case april: 
		case june:
		case september: 
		case november:
			days = 30;
			break; 
		case february:
			days = 28;
			break; 
		default:
			NSLog (@"bad month number"); days = 0;
			break;
	}
	if ( days != 0 )
		NSLog (@"Number of days is %i", days);
	if ( amonth == february )
		NSLog (@"...or 29 if it's a leap year");
	
	return 0;
} 



- 타입무효(void)

void 타입은 사용 가능한 값이 없음을 지정하며, 아래와 같은 상황에서 사용된다.



- 파생타입(Derived types)

  • 배열 (Array)

    같은 타입의 요소들을 순차적으로 저장하는 고정크기의 컬렉션

    배열 변수 선언 후 숫자를 사용하여 표현하며, 배열 특정 요소는 인덱스에 의해 엑세스가 가능함.

    가장 낮은 주소는 첫 번째 요소, 가장 높은 주소는 마지막 요소이다.

    배열의 선언법과 초기화 방법은 아래와 같다.

    타입 배열이름 [크기];
    double balance[10] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 
    8.0, 9.0, 10.0};
    
    double ssef[] = {2.2, 3.3};
    NSLog(@"1번째 요소값 = %f\n", ssef[1]);
    //3.3 출력

    배열의 size는 0보다 큰 정수 상수, type은 유효한 Objective-C 데이터 유형(int, double 등등)만 가능하다.

    또한, 배열의 초기화시에 대괄호에 숫자를 넣어 size를 지정해 줄 수 있으며, 대괄호 안에 숫자를 넣지 않으면 중괄호에 선언된 값들 개수만큼 크기가 자동으로 설정된다.

    아래는 배열을 활용한 예제 코드이다.

    #import <Foundation/Foundation.h>
     int main(int argc, const char * argv[]) {
    	@autoreleasepool {
    		
    		int myArray[10];
    		int i, j;
    		
    		for (i=0; i<10; i++) {
    			 myArray[i] = i + 100;
    		}
    
    		for (j = 0; j < 10; j++) {
    			NSLog(@"Element[%d] = %d\n", j, myArray[j]);
    		}
    	}
    	return 0;
    }

    추가로 위 코드에서 @autorelease는 프로그램의 최고 메모리 사용량을 줄여주는 역할을 한다고 한다.
    (주로 loop 문에서 많이 쓰인다)

    또한, 배열은 아래와 같이 다양한 형태로 존재할 수 있다.

  • 포인터 (Pointer)

    변수의 메모리 위치를 값으로 가지는 변수

    포인터의 선언 방식은 아래와 같다.

    type *var-name;

    여기서 type에는 Int, Double 등과 같은 유효한 데이터 타입이 와야한다.

    var-name은 포인터 변수의 이름을 의미한다.

    아래는 포인터를 활용한 예제 코드들이다.

    #import <Foundation/Foundation.h>
    int main(int argc, const char * argv[]) {
    	int age = 13;
    	double height = 145.32;
    	
    	//변수에 담긴 값을 출력
    	NSLog(@"age : %d", age);
    	NSLog(@"height : %f", height);
    	
    	//변수가 위치한 메모리 안에서의 주소
    	NSLog(@"address of age : %x", &age);
    	NSLog(@"address of height : %x", &height);
    
    	//포인터 정보 -> 해당 데이터의 메모리 주소 + 메모리를 차지하는 크기
    	//토지대장 느낌
    	return 0;
    }
    //13, 145.320000
    // 6fdff3ac, 6fdff3a0 (16진수로 표현된 메모리 주소)
    #import <Foundation/Foundation.h>
    int main(int argc, const char * argv[]) {
    	int age = 17;
    	
    	// 변수 age의 주소를 확인해서, int 타입이 담길 거라고 생각하는 포인터 변수 만들기
    	int *addressOfAge = &age;
    	
    	NSLog(@"age는 %p 주소에 위치했습니다.", addressOfAge);
    	NSLog(@"age 변수의 메모리 크기 %zu 바이트입니다.", sizeof(age));
    	NSLog(@"int의 메모리 크기 %zu 바이트입니다.", sizeof(int));
    	NSLog(@"처음 %p 주소에 가보니 %d 값이 들어있습니다.", addressOfAge, *addressOfAge);
    	//0X16fdff3ac
    	//0X16fdff3ac, 17
    
    	
    	addressOfAge = 32;
    	//오류나는 문장 -> 포인터 타입 아닌 Int 타입이 들어가기 때문에 
    	
    	*addressOfAge = 32;
    	//옳은 문장 ->
    	
    	NSLog(@"다시 %p 주소에 가보니 %d 값이 들어있습니다.", addressOfAge, *addressOfAge);
    	NSLog(@"%p를 담은 데이터의 포인터정보의 메모리 크기 %zu 바이트입니다.", infoOfAge, sizeof(infoOfAge));
    	NSLog(@"int를 담은 데이터의 포인터정보 크기는 %zu 바이트입니다.", sizeof(int*));
    
    	//SampleClass의 인스턴스를 만들어서 그 메모리의 위치정보를 SampleClass클래스에 맞춘 포인터 변수 
    	// sampleClass에 할당함
    	// 클래스에 의해 만들어지는 인스턴스는 무조건 포인터 단위로 관리해야만 활용 가능함.
    	SampleClass *sampleClass = [[SampleClass alloc] init];
    	//alloc, init에 의해 모두 주소값이 반환됨
    
    	//sampleClass 포인터 정보가 가르키는 인스턴스 데이터를 찾아가서
    	//데이터에 명시된 sayHello 메소드를 실행하라
    	[sampleClass sayHello];
    
    	return 0;
    }  

    위 코드를 통해 살펴볼 수 있는 포인터의 특성들은 아래와 같다.

    -특정 변수의 메모리 주소는 앰퍼서더(&) 로 접근한다.

    - 메모리주소는 16진수 값으로 표현되기에 %p 뿐만 아니라 %x 로 출력할 수 있다.

    - 포인터 변수에 담긴 메모리 주소에 담긴 값에 접근할 땐 포인터 변수 앞에 * 을 붙인다.

    - size에 대응하는 형식지정자는 %zu 이다.

    - 포인터를 통해 출력한 주소 값의 크기는 주소에 담긴 값의 타입과 상관없이 항상 8byte이다.

    (주소 값은 16진수로 표현되기 때문이다)

    Objective-C에서는 포인터에 할당할 정확한 주소가 없는 경우 포인터 변수에 NULL 값을 할당 할 수도 있는데, 우리는 이를 NULL 포인터 라고 부른다.

    NULL 포인터는 메모리 주소 값으로 0을 가지는데, 이는 포인터가 액세스 가능한 메모리 위치를 가리키도록 의도되지 않았음을 의미한다.

    NULL 포인터를 공부하면서 개인적으로 Swift에서의 nil과 굉장히 헷갈렸는데 둘의 차이점을 살펴보면 아래와 같다.

    NULLnil
    주소가 없음을 의미내용이 없음을 의미



    포인터는 아래에 적힌 다양한 형태들로 존재할 수 있다.


📌 변수와 상수

변수와 상수의 개념은 Swift, C 등 다른 프로그래밍 언어와 동일하며, 선언 방식도 비슷하다.

그렇기에 본 포스팅에선 가볍게 살펴보는 정도로만 변수와 상수 개념을 다루겠다.

- 변수

변수 : 값을 저장하는 저장 영역에 주어진 이름, 변경이 가능

아래는 변수를 선언 및 출력하는 예제코드이다.

#import <Foundation/Foundation.h>

// Variable declaration:
extern int a, b;
extern int c;
extern float f;

int main () {
  /* variable definition: */
  int a, b;
  int c;
  float f;
 
  /* actual initialization */
  a = 10;
  b = 20;
  
  c = a + b;
  NSLog(@"value of c : %d \n", c);

  f = 70.0/3.0;
  NSLog(@"value of f : %f \n", f);
 
  return 0;
}

여기서 extern어느 곳에서나 변수를 선언할 수 있다는 것을 의미하는 키워드이다.

변수를 선언할 때 등호 왼쪽에 위치한 메모리 위치를 참조하는 표현식lvalue 라고 한다.

변수를 선언할 때 등호 오른쪽에 위치한 메모리의 일부 주소에 저장된 데이터 값rvalue 라고 한다.

- 상수

상수 : 프로그램이 실행 중에 변경할 수 없는 고정 값

상수는 정수, 문자, 부동 소수점 또는 문자열 리터럴과 같은 기본 데이터 유형 중 하나일 수 있으며, 열거형 상수도 있다.

이때 리터럴이란, 해당 타입의 원형(타입의 값 그자체)을 말한다.

  • 정수 리터럴

    정수 리터럴은 10/8/16진수 상수일 수 있고, 기수를 접두사로 지정한다.
    (0 : 8진수 접두사, 0x : 16진수 접두사, 10진수는 접두사 없음)

    또한, unsigned와 long에 대해 U와 L의 조합인 접미사도 가질 수 있다.
    (U와 L은 소문자도 될 수 있다)

    아래는 정수 리터럴의 몇가지 예시이다.


  • 부동 소수점 리터럴

    부동 소수점 리터럴에는 정수 부분, 소수점, 소수 부분 및 지수 부분이 있다.

    나타내는 방법은 소수점 형식과 지수 형식이 있다.

    소수점 형식을 사용하여 나타낼 때는 소수점, 지수 또는 둘 다를 포함해야 함.

    지수 형식을 사용하여 나타낼 때는 정수 부분, 소수 부분 또는 둘 다를 포함해야 함.

    부호가 있는 지수는 e 또는 E로 시작한다.

    아래는 부동 소수점 리터럴의 몇가지 예시이다.

  • 문자 리터럴

    문자 리터럴은 작은 따옴표(') 에 묶여 있으며 char 유형의 단순 변수에 저장이 가능하다.

    일반문자('x'), 이스케이프 시퀀스('\t'), 범용문자('\u02C0')이 있다.

  • 문자열 리터럴

    문자열 리터럴 또는 상수는 큰 따옴표("") 로 묶인다.

    문자열에는 문자 리터럴들이 포함된다.


  • 상수 정의법

    1. #define

    #define identifier value

    컴파일 시점에 코드의 모든 identifier를 value로 바꿔버리는 방식으로 상수를 정의한다.

    전통적인 C언어에서는 많이 쓰이지만, Objective-C에서는 사용이 지양된다.

    2. const 키워드

    const type variable = value;
    
    #import <Foundation/Foundation.h>
    
    int main() {
    	const int LENGTH = 10;
       const int WIDTH = 5;
       const char NEWLINE = "\n";
       int area;
       
       area = LENGTH * WIDTH;
       NSLog(@"value of area : %d", area);
       NSLog(@"%c", NEWLINE);
       
       return 0;
    }

    const 키워드를 이용해 상수를 정의하면 코드 작동 중에 선언이 이루어지기 때문에, #define 보다 안전하다.

    Objective-C에서는 const 키워드 사용을 권장한다.

    그리고 Objective-C에서 상수이름은 대문자로 해야한다.


📌 반복문과 조건문

반복문과 조건문도 상수와 변수처럼 다른 언어들과 특성이 비슷하다.

따라서, 반복문과 조건문에 관한 간단한 코드예제들만 살펴보고 넘어가겠다.

- 반복문 (Loops)

Objective-C에서 사용할 수 있는 반복문의 종류는 아래와 같다.

- while문

- for문

- do...while문

그리고 이러한 반복문은 다음과 같은 제어문도 지원한다.

- break

- continue



  • while 문

    #import <Foundation/Foundation.h>
    
    int main ()
    {
       int a = 10;
       
       while( a < 20) {
           NSLog(@"value of a: %d\n", a);
           a++;
           
           if (a > 15) {
               break;
           }
       }
    }

    while 옆의 소괄호 안의 조건이 true인 경우에 한해 계속해서 반복문이 돌아간다.

    하지만, a가 15이상이 된다면 break 제어문에 걸리게 된다.

    여기서 break반복문에서 탈출하라는 것을 의미한다.

  • do-while문

    #import <Foundation/Foundation.h>
    int main ()
    {
       int a = 10;
       
       do {
           if( a == 15 ) {
               a = a + 1;
               continue;
           }
           NSLog(@"value of a: %d\n", a);
           a++;
       }while( a < 20 );
    
       return 0;
    }

    do-while문의 가장 큰 특징은, while 옆의 조건이 true든지 false든지 간에 do 중괄호 안에 들어있는 구문을 일단 먼저 실행한다는 것이다.

    만일 do에 있는 구문이 실행되었는데, while 옆의 조건이 false이게 된다면, do-while 반복문은 종료된다.

    그리고 코드 중간에 continue 라는 제어문이 있는데, 이는 continue 이후에 나오는 나머지 코드들을 건너뛰고 위의 즉시 조건을 다시 테스트하게끔 한다.

    Swift의 repeat-while과 거의 흡사한 형식이다.


  • for문

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            int n, number, triangularNumber;
            NSLog(@"Whata&number);
    	    triangularNumber = 0;
            
          for(n=1; n <= number; ++n)
                triangularNumber += n;
            
          NSLog(@"NUMBER %i is %i\n", number, triangularNumber);
        }
        return 0;
    }

    C언어의 for문과 형식이 똑같다.





for 옆 소괄호에는 (초기화 된 값, 값 조건, 증감여부)를 알려주어서 초기화 된 값이 값 조건을 만족하지 못 할때까지 반복문이 실행된다.

좀 더 반복문을 응용해보면, Objective-C에서는 이러한 반복문들을 중첩시켜서 중첩반복문도 생성할 수 있게 해준다.


- 조건문 (Decision Making)

Objective-C에서는 다음과 같은 조건문들이 있다.

- if문

- if...else문

- switch문



  • if & if-else 문

    #import <Foundation/Foundation.h>
    
    int main ()
    {
       int a = 30;
       
       if(a < 20) {
           NSLog(@"a는 20보다 작습니다.");
       } else if (a < 40) {
           NSLog(@"a는 40보다 작고 20보다 크거나 같습니다.");
       } else {
           NSLog(@"a는 40보다 크거나 같습니다.");
       }
       
       NSLog(@"a는 %d입니다.", a);
       
       return 0;
    }
  • switch 문

    #import <Foundation/Foundation.h>
    int main ()
    {
       char grade = 'B';
       
       switch(grade) {
           case 'A':
               NSLog(@"잘함");
               break;
           case 'B':
               NSLog(@"적당");
               break;
           case 'C':
               NSLog(@"섭섭");
               break;
           case 'D':
               NSLog(@"재수강");
               break;
           case 'F':
               NSLog(@"자퇴는 능지순");
               break;
           default:
               NSLog(@"??");
               break;
       }
       
       NSLog(@"학점은 %c", grade);
       
       return 0;
    }

    switch 옆 소괄호 안의 값(grade)에 따라 해당 값에 대응되는 case 안의 구문을 실행한다.

    switch문의 case 구문을 작성할 때는 break;를 반드시 적어줘야한다.

    break;를 적어주지 않으면 switch문이 멈추지 않고 계속 실행되기 때문이다.

    Swift는 break;를 적지 않아도 한 번 실행하면 바로 switch문이 끝났다는 점에서 차이가 있다고 볼 수 있다.


📌 함수

작업을 함께 수행하는 명령문의 그룹



- 함수 정의하기

- (리턴타입) 메서드이름:(인수타입1) 인자이름1 결합인수2:(인수타입2)... {
	//함수내용
}
  • 리턴타입 : 함수가 반환하는 값의 타입

  • 메서드이름 : 메서드의 실제 이름

  • 인수 : 자리 표시자, 함수가 호출될 때 값이 전달되는 곳

  • 결합 인수 : 함수를 호출하는 동안 읽기 쉽고 명확하게 하기 위한 것

  • 메서드 본문 : 메서드가 수행하는 작업을 수행하는 명령문 모음<

아래는 함수 선언 및 구현의 예제코드이다.

#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/* method declaration */
- (int)max:(int)num1 andNum2:(int)num2;
@end

@implementation SampleClass
/* method returning the max between two numbers */
- (int)max:(int)num1 andNum2:(int)num2 {
 /* local variable declaration */
 int result;

 if (num1 > num2) {
 result = num1;
 } else {
 result = num2;
 }

 return result;
}
@end



- 함수 호출하기

함수에 정의된 작업을 수행하고 싶으면 해당 함수를 직접 호출해야 한다.

Objective-C에서 함수 호출은 다음과 같은 방식으로 할 수 있다.

[인스턴스이름 메서드:인자1 결합인자2:인자2..];

아래는 함수 호출에 관련된 예제코드이다.

int main () {

 /* local variable definition */
 int a = 100;
 int b = 200;
 int ret;

 SampleClass *sampleClass = [[SampleClass alloc]init];
 /* calling a method to get max value */
 ret = [sampleClass max:a andNum2:b];

 NSLog(@"Max value is : %d\n", ret );
 return 0;
}



- 함수의 인수

함수를 호출하는 동안 인수를 함수에 전달하는 방법은 2가지가 있다.

Objective-C는 이 둘 중에서 Call by value를 사용해 인수를 전달한다.

Call by value는 함수 내의 코드가 함수를 호출하는 데 사용되는 인수를 변경할 수 없음을 의미한다.


📌 블록

클로저의 '조상'

Objective-C 클래스는 관련동작과 데이터를 결합하는 개체를 정의한다.

하지만, 때로는 메서드 모음이 아닌 단일 작업이나 동작 단위를 나타내는 것이 합리적이다.

이럴때 쓰기 좋은 것이 바로 '블록'이다.

블록을 사용하면 값인 것처럼 메서드나 함수에 전달할 수 있는 고유한 코드 세그먼트를 만들 수 있다.

- 블록 선언 및 호출

returntype (^blockName)(argumentType)= ^{};
//선언방식

void (^simpleBlock)(void) = ^{
	NSLog(@"This is a block");
};
//구현

simpleBlock();
//호출

블록은 아래와 같이 함수와 마찬가지로 인수를 사용하고 값을 반환할 수 있다.

double (^multiplyTwoValues)(double, double) = ^(double firstValue,
double secondValue) {
	return firstValue * secondValue;
};

double result = multiplyTwoValues(2,4);
NSLog(@"The result is %f", result);

// 타입이름 (^이름) (파라미터) = ^(인수) { 내용};

📌 숫자

기본 데이터 유형을 객체 형태로 저장하기 위한 방법

Objective-C에서는 NSNumber를 통해 기본 데이터 유형을 객체 형태로 저장할 수 있게끔 해준다.

아래는 위의 NSNumber 메서드를 활용한 예제코드이다.

@interface SampleClass : NSObject
//Foundation이 제공하는 NSObject를 상속받은 SampleClass는 이러한 내용을 구현함
- (NSNumber *) multiplyA: (NSNumber *)a withB:(NSNumber *)b;
@end
//매개변수로 double, float이 올수도 있음
//NSNumber를 활용하면 해결가능(Foundation에서 제공)


//SampleClass의 구체적인 내용은 다음과 같습니다.
@implementation SampleClass
	- (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b {
	//NSNumber 타입으로 받은 a, b로부터 float 값들을 꺼내서 곱셈한 후
	//NSNumber로 다시 만들어 반환함		
		float number1 = [a floatValue]; //NSNumber -> float 으로 변환됨
		float number2 = [a floatValue];
		float product = number1 * number2;

		//결과를 NSNumber로 다시 만들어 반환 -> numberWithFloat 활용
		NSNumber *result = [NSNumber numberWithFloat:product];
		return result;
}
@end

int main(int argc, const char * argv[]) {
	@autoreleasepool {
		NSLog(@"Hello, world!");
		
		SampleClass *sampleClass = [[SampleClass alloc] init];
//객체를 생성하는 코드[[객체 alloc]init]
		//swift였다면.. var sampleClass: SampleClass = SampleClass()

		NSNumber *a = [NSNumber numberWithFloat:10.5];
		NSNumber *b = [NSNumber numberWithFloat:10.0];
		//float->NSNumber 객체로 만들어준다
		NSNumber *result = [sampleClass multiplyA:a withB:b];

		//결과의 NSNumber로부터 NSString을 만들어 활용 및 출력
		NSString *resultString = [result stringValue];
		NSLog(@"The product is %@", resultString);
	return 0;
}
profile
iOS🍎

0개의 댓글