program tip

Objective-C에서 nil에 메시지 보내기

radiobox 2020. 8. 11. 08:13
반응형

Objective-C에서 nil에 메시지 보내기


Apple의 Objective-C 2.0 문서를 읽고있는 Java 개발자로서 " 메시지를 nil에 보내는 것"이 무엇을 의미 하는지 궁금 합니다. 실제로 어떻게 유용한지는 말할 것도 없습니다. 문서에서 발췌 :

Cocoa에는이 사실을 이용하는 몇 가지 패턴이 있습니다. 메시지에서 nil로 반환 된 값도 유효 할 수 있습니다.

  • 메서드가 객체, 포인터 유형, sizeof (void *)보다 작거나 같은 크기의 정수 스칼라, float, double, long double 또는 long long을 반환하면 nil로 전송 된 메시지는 0을 반환합니다. .
  • 메서드가 Mac OS X ABI 함수 호출 가이드에 정의 된대로 레지스터에 반환되는 구조체를 반환하는 경우 nil로 전송 된 메시지는 데이터 구조의 모든 필드에 대해 0.0을 반환합니다. 다른 구조체 데이터 유형은 0으로 채워지지 않습니다.
  • 메서드가 앞서 언급 한 값 유형 이외의 것을 반환하는 경우 nil로 전송 된 메시지의 반환 값은 정의되지 않습니다.

Java가 위의 설명을 무시할 수 없도록 내 두뇌를 만들었습니까? 아니면 이것을 유리처럼 선명하게 만드는 내가 놓친 것이 있습니까?

Objective-C에서 메시지 / 수신자에 대한 아이디어를 얻었습니다. 수신자가 nil.


글쎄요, 매우 인위적인 예를 사용하여 설명 할 수 있다고 생각합니다. ArrayList의 모든 요소를 ​​출력하는 Java 메서드가 있다고 가정 해 보겠습니다.

void foo(ArrayList list)
{
    for(int i = 0; i < list.size(); ++i){
        System.out.println(list.get(i).toString());
    }
}

이제 그 메서드를 다음과 같이 호출하면 : someObject.foo (NULL); 목록에 액세스하려고 할 때 NullPointerException이 발생합니다.이 경우 list.size (); 이제는 NULL 값을 사용하여 someObject.foo (NULL)를 호출하지 않을 것입니다. 그러나 someObject.foo (otherObject.getArrayList ());와 같은 ArrayList 생성 오류가 발생하면 NULL을 반환하는 메서드에서 ArrayList를 얻었을 수 있습니다.

물론 다음과 같은 작업을 수행하면 문제가 발생합니다.

ArrayList list = NULL;
list.size();

이제 Objective-C에는 동일한 방법이 있습니다.

- (void)foo:(NSArray*)anArray
{
    int i;
    for(i = 0; i < [anArray count]; ++i){
        NSLog(@"%@", [[anArray objectAtIndex:i] stringValue];
    }
}

이제 다음 코드가 있다면 :

[someObject foo:nil];

Java가 NullPointerException을 생성하는 것과 동일한 상황이 있습니다. nil 객체는 [anArray count]에서 먼저 액세스됩니다. 그러나 NullPointerException을 던지는 대신 Objective-C는 위의 규칙에 따라 단순히 0을 반환하므로 루프가 실행되지 않습니다. 그러나 설정된 횟수만큼 실행되도록 루프를 설정하면 먼저 [anArray objectAtIndex : i]에서 anArray에 메시지를 보냅니다. 이것은 또한 0을 반환하지만 objectAtIndex :는 포인터를 반환하고 0에 대한 포인터는 nil / NULL이므로 NSLog는 루프를 통해 매번 nil로 전달됩니다. (NSLog는 메소드가 아니라 함수이지만 nil NSString을 전달하면 (null) 출력합니다.

어떤 경우에는 NullPointerException이있는 것이 더 좋습니다. 프로그램에 문제가 있음을 즉시 알 수 있기 때문에 예외를 포착하지 않으면 프로그램이 충돌합니다. (C에서 이러한 방식으로 NULL을 역 참조하려고하면 프로그램이 충돌합니다.) Objective-C에서는 대신 잘못된 런타임 동작이 발생할 수 있습니다. 그러나 0 / nil / NULL / 0으로 된 구조체를 반환해도 중단되지 않는 메서드가있는 경우 개체 또는 매개 변수가 nil인지 확인하지 않아도됩니다.


메시지에는 nil아무 것도 반환하지 않습니다 nil, Nil, NULL, 0, 또는 0.0.


다른 모든 게시물은 정확하지만 여기서 중요한 것은 개념 일 수 있습니다.

Objective-C 메서드 호출에서 선택기를 허용 할 수있는 모든 개체 참조는 해당 선택기에 대한 유효한 대상입니다.

이렇게하면 "대상 개체가 X 유형입니까?"라는 많은 비용이 절약됩니다. 코드-수신 객체가 선택기를 구현하는 한 어떤 클래스인지 전혀 차이가 없습니다 ! nil어떤 선택을 받아 그 NSObject라는 것입니다 - 그냥하지 않습니다 것을. 이렇게하면 "없음 확인, 참이면 메시지 전송 안 함"코드도 많이 제거됩니다. ( "만약 그것이 그것을 받아들이면 그것을 구현한다"개념은 또한 일종의 자바 인터페이스와 비슷한 프로토콜 을 생성 할 수있게 해준다 : 클래스가 명시된 메소드를 구현하면 프로토콜을 준수한다는 선언이다.)

그 이유는 컴파일러를 행복하게 유지하는 것 외에는 아무것도하지 않는 원숭이 코드를 제거하기 위해서입니다. 예, 메서드 호출이 하나 더 발생하면 오버 헤드가 발생하지만 프로그래머 시간 을 절약 할 수 있습니다 . 이는 CPU 시간보다 훨씬 더 비싼 리소스입니다. 또한 애플리케이션에서 더 많은 코드와 더 많은 조건부 복잡성을 제거하고 있습니다.

비추천 사용자를위한 설명 : 이것이 좋은 방법이 아니라고 생각할 수 있지만 언어가 구현되는 방식 이며 Objective-C에서 권장되는 프로그래밍 관용구 입니다 (Stanford iPhone 프로그래밍 강의 참조).


의미하는 바는 objc_msgSend가 nil 포인터에서 호출 될 때 런타임이 오류를 생성하지 않는다는 것입니다. 대신 (종종 유용한) 값을 반환합니다. 부작용이있을 수있는 메시지는 아무 작업도 수행하지 않습니다.

대부분의 기본값이 오류보다 더 적절하기 때문에 유용합니다. 예를 들면 :

[someNullNSArrayReference count] => 0

즉, nil은 빈 배열로 보입니다. nil NSView 참조를 숨기는 것은 아무것도하지 않습니다. 핸디, 응?


문서의 인용문에는 두 개의 개별 개념이 있습니다. 문서에서 더 명확하게 설명하면 더 좋을 수 있습니다.

Cocoa에는이 사실을 이용하는 몇 가지 패턴이 있습니다.

메시지에서 nil로 반환 된 값도 유효 할 수 있습니다.

전자가 여기서 더 관련이있을 수 있습니다. 일반적으로 nil코드를보다 간단하게 만들기 위해 메시지를 보낼 수 있습니다. 모든 곳에서 null 값을 확인할 필요가 없습니다. 표준 예제는 아마도 접근 자 메서드 일 것입니다.

- (void)setValue:(MyClass *)newValue {
    if (value != newValue) { 
        [value release];
        value = [newValue retain];
    }
}

If sending messages to nil were not valid, this method would be more complex -- you'd have to have two additional checks to ensure value and newValue are not nil before sending them messages.

The latter point (that values returned from a message to nil are also typically valid), though, adds a multiplier effect to the former. For example:

if ([myArray count] > 0) {
    // do something...
}

This code again doesn't require a check for nil values, and flows naturally...

All this said, the additional flexibility that being able to send messages to nil does come at some cost. There is the possibility that you will at some stage write code that fails in a peculiar way because you didn't take into account the possibility that a value might be nil.


From Greg Parker's site:

If running LLVM Compiler 3.0 (Xcode 4.2) or later

Messages to nil with return type | return
Integers up to 64 bits           | 0
Floating-point up to long double | 0.0
Pointers                         | nil
Structs                          | {0}
Any _Complex type                | {0, 0}

It means often not having to check for nil objects everywhere for safety - particularly:

[someVariable release];

or, as noted, various count and length methods all return 0 when you've got a nil value, so you do not have to add extra checks for nil all over:

if ( [myString length] > 0 )

or this:

return [myArray count]; // say for number of rows in a table

Don't think about "the receiver being nil"; I agree, that is pretty weird. If you're sending a message to nil, there is no receiver. You're just sending a message to nothing.

How to deal with that is a philosophical difference between Java and Objective-C: in Java, that's an error; in Objective-C, it is a no-op.


ObjC messages which are sent to nil and whose return values have size larger than sizeof(void*) produce undefined values on PowerPC processors. In addition to that, these messages cause undefined values to be returned in fields of structs whose size is larger than 8 bytes on Intel processors as well. Vincent Gable has described this nicely in his blog post


I don't think any of the other answers have mentioned this clearly: if you're used to Java, you should keep in mind that while Objective-C on Mac OS X has exception handling support, it's an optional language feature that can be turned on/off with a compiler flag. My guess is that this design of "sending messages to nil is safe" predates the inclusion of exception handling support in the language and was done with a similar goal in mind: methods can return nil to indicate errors, and since sending a message to nil usually returns nil in turn, this allows the error indication to propagate through your code so you don't have to check for it at every single message. You only have to check for it at points where it matters. I personally think exception propagation&handling is a better way to address this goal, but not everyone may agree with that. (On the other hand, I for example don't like Java's requirement on you having to declare what exceptions a method may throw, which often forces you to syntactically propagate exception declarations throughout your code; but that's another discussion.)

I've posted a similar, but longer, answer to the related question "Is asserting that every object creation succeeded necessary in Objective C?" if you want more details.


C represents nothing as 0 for primitive values, and NULL for pointers (which is equivalent to 0 in a pointer context).

Objective-C builds on C's representation of nothing by adding nil. nil is an object pointer to nothing. Although semantically distinct from NULL, they are technically equivalent to one another.

Newly-alloc'd NSObjects start life with their contents set to 0. This means that all pointers that object has to other objects begin as nil, so it's unnecessary to, for instance, set self.(association) = nil in init methods.

The most notable behavior of nil, though, is that it can have messages sent to it.

In other languages, like C++ (or Java), this would crash your program, but in Objective-C, invoking a method on nil returns a zero value. This greatly simplifies expressions, as it obviates the need to check for nil before doing anything:

// For example, this expression...
if (name != nil && [name isEqualToString:@"Steve"]) { ... }

// ...can be simplified to:
if ([name isEqualToString:@"Steve"]) { ... }

Being aware of how nil works in Objective-C allows this convenience to be a feature, and not a lurking bug in your application. Make sure to guard against cases where nil values are unwanted, either by checking and returning early to fail silently, or adding a NSParameterAssert to throw an exception.

Source: http://nshipster.com/nil/ https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html (Sending Message to nil).

참고URL : https://stackoverflow.com/questions/156395/sending-a-message-to-nil-in-objective-c

반응형