30 April 2014

nil과 null

오브젝티브C에서 nil은 객체 참조에 사용되고 null은 기타 다른 포인터 자료형에 사용합니다.

//nil 사용
MyClass *obj = nil

// null 사용
int *ptr = NULL;

만일 nil 포인터를 사용해 메모리 주소에 접근하려고 하면 메모리 주소 오류(memory address violation)가 발생합니다. 주소 오류는 하드웨어 수준에서 검출하며, 해당 프로세스에게 SIGBUS 시그널을 보내고 해당 프로세스는 즉시 종료됩니다. 시스템의 CrashReport 데몬은 SIGBUS 시그널을 감지하여 SIGBUS를 받은 프로세스의 종료 직전 상태를 수집해 오류 보고서를 자동으로 작성합니다.

nil에 메시지 전달

오브젝티브C에서는 nil 객체 포인터에도 메시지를 보낼 수 있으며 nil에 메시지를 보내도록 권장합니다. 왜냐하면 수신자 값이 nil이라면 메시지 전달 함수가 멈추고 nil이나 0, NO값을 반환합니다.

따라서 수신자가 nil이 아닌지 확인해야할 필요가 없습니다. 수신자가 nil이 아닌지 이미 확인하고 보내므로 개발자가 nil인지 확인할 필요가 없게 됩니다.

그러나 메시지를 보내고 처리되는 로직이 nil이 아닌 경우에 대해서 처리해야 한다면 메시지를 전달하기전에 nil 여부를 직접 확인해야 합니다.

하지만 nil 특성을 이용해 프로그램을 구성하려면 프로퍼티 접근자(property accessor), 부재중 동작(absent behavior), 아무것도 없는 일관성(consistency with nothing) 등의 세가지 원칙을 지키는게 좋습니다.

프로퍼티 접근자

nil 수신자에 메시지를 전송하면 0이나 nil값을 반환받으므로 호출해도 문제는 없습니다. 그러나 meal->receipt와 같이 직접 접근을 하여 변수에 객체 포인터가 아닌 nil이 설정되며 메모리 주소 오류가 발생하여 다운됩니다.

부재중 동작

객체가 nil인 경우를 대비하여 추가적인 동작을 지정해야하는 경우도 있습니다.

  • 로그 출력 객체가 설정되어 있다면 메시지를 로그에 출력하고 nil로 설정되면 아무런 작업을 하지 않습니다.

  • 리스너 객체는 설정된 상태에서만 변경된 정보에 대한 메시지를 전송하고 nil로 설정되면 더이상 변경 사항이 전달되지 않습니다.

  • 위임 객체는 설정된 상태에서만 위임 객체 기능을 호출하고 없으면 기본 기능만 호출합니다.

없음의 일관성

클래스의 프로퍼티는 nil이나 0을 없는 객체로 일관되게 설계를 해야합니다. 따라서 프로퍼티는 긍적적인 값을 표현하게 프로퍼티를 정의하라는 의미이며, isEmpty라는 메소드 대신 hasObject라는 메소드 형식으로 정의하는 것이 좋습니다.


정리

nil 수신자를 다루게 되면 좀 더 간결하고 안전한 코드를 작성할 수 있지만 제대로 활용할만큼 적용하려면 시간이 필요할 수 있습니다.



※ 자바개발자를 위한 오브젝티브C 책을 참고하였습니다.