[ios] ‘인스턴스로 전송 된 인식 할 수없는 선택기’오류를 디버그하려면 어떻게해야합니까?

내 테이블보기에 대한 사용자 지정 테이블 셀보기를 만들고 있습니다. 사용자 지정 셀 (스토리 보드)의 이미지보기를 신속하게 코드에 연결하면 다음 오류가 발생합니다.

[UITableViewCellContentView image]: unrecognized selector sent to instance 0x7fb4fad7fd20'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010ccbb3f5 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010e7e9bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010ccc250d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x000000010cc1a7fc ___forwarding___ + 988
    4   CoreFoundation                      0x000000010cc1a398 _CF_forwarding_prep_0 + 120
    5   UIKit                               0x000000010d7d8881 -[UITableViewCell _marginWidth] + 151
    6   UIKit                               0x000000010d7ca23d -[UITableViewCell _separatorFrame] + 70
    7   UIKit                               0x000000010d7ca6fa -[UITableViewCell _updateSeparatorContent] + 360
    8   UIKit                               0x000000010d7d4e85 -[UITableViewCell _setSectionLocation:animated:forceBackgroundSetup:] + 1174
    9   UIKit                               0x000000010d634ea8 __53-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke + 1822
    10  UIKit                               0x000000010d5b5eae +[UIView(Animation) performWithoutAnimation:] + 65
    11  UIKit                               0x000000010d63477b -[UITableView _configureCellForDisplay:forIndexPath:] + 312
    12  UIKit                               0x000000010d63bcec -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 533
    13  UIKit                               0x000000010d61b7f1 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2846
    14  UIKit                               0x000000010d63165c -[UITableView layoutSubviews] + 213
    15  UIKit                               0x000000010d5be199 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 521
    16  QuartzCore                          0x00000001114b6f98 -[CALayer layoutSublayers] + 150
    17  QuartzCore                          0x00000001114abbbe _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
    18  QuartzCore                          0x00000001114aba2e _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
    19  QuartzCore                          0x0000000111419ade _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 242
    20  QuartzCore                          0x000000011141abea _ZN2CA11Transaction6commitEv + 390
    21  QuartzCore                          0x000000011141b255 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 89
    22  CoreFoundation                      0x000000010cbf0347 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
    23  CoreFoundation                      0x000000010cbf02a0 __CFRunLoopDoObservers + 368
    24  CoreFoundation                      0x000000010cbe60d3 __CFRunLoopRun + 1123
    25  CoreFoundation                      0x000000010cbe5a06 CFRunLoopRunSpecific + 470
    26  GraphicsServices                    0x0000000110daa9f0 GSEventRunModal + 161
    27  UIKit                               0x000000010d545550 UIApplicationMain + 1282
    28  TestWork                          0x000000010caa432e top_level_code + 78
    29  TestWork                          0x000000010caa436a main + 42
    30  libdyld.dylib                       0x000000010efc3145 start + 1
    31  ???                                 0x0000000000000001 0x0 + 1
)

이 오류를 해결하는 방법을 알려주시겠습니까?

감사합니다.

내 프로젝트에 예외 중단 점을 추가합니다.

이것이 끊어지는 선입니다.

  override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = self.tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as ItemTableViewCell  <---------------

하지만 내 코드에서 ‘이미지’를 사용하지 않습니다.



답변

에서 기호 중단 점을 설정해보십시오 -[NSObject(NSObject) doesNotRecognizeSelector:]. [+]중단 점을 추가하려면 Breakpoint Navigator의 왼쪽 하단 모서리를 클릭하기 만하면 됩니다. 그런 다음 ‘Add Symbolic Breakpoint’를 클릭합니다. 지금 충돌을 재현하면 코드에서 문제가 발생한 위치를 더 잘 알 수 있습니다.

여기에 이미지 설명 입력


답변

을 사용하여 이러한 충돌을 쉽게 추적 할 수 있습니다 Exception Breakpoints.

열고 Breakpoint Navigator추가

여기에 이미지 설명 입력

Exception Breakpoint를 추가하면 Exception.

여기에 이미지 설명 입력

을 선택 Objective-C합니다.

코드를 실행하고 애플리케이션을 크래시하면 중단 점이 코드가 크래시되는 지점까지 중지합니다.


답변

중요한 첫 번째 단계는 오류 메시지를 분석하는 것입니다.

[UITableViewCellContentView image]: unrecognized selector sent to instance

이것은 “메시지” image가 UITableViewCellContentView 클래스의 객체로 “보냈다”는 것을 알려줍니다 . (즉, imageUITableViewCellContentView 클래스의 개체에 대해 메서드를 호출하려고했습니다 .)

가장 먼저 물어봐야 할 것은 “이게 말이 되나?”입니다. 명명 된 클래스에 Image메서드가 있지만 image메서드가 없어서 호출에 잘못된 메서드 이름이 사용되었을 수 있습니다. 또는 명명 된 메서드가 someMethod:someParm:이지만 클래스가을 구현할 수 있습니다 someMethod:someParm:anotherParm:. 이는 호출에서 매개 변수가 생략되었음을 의미합니다.

그러나 대부분의 경우 명명 된 클래스에는 명명 된 메서드와 모호하게 유사한 메서드가 없습니다. 이는 실패한 호출에서 잘못된 개체에 대한 포인터가 사용되었음을 의미합니다.

예를 들어 다음과 같이 할 수 있습니다.

NSArray* myArray = [myDictionary objectForKey:@"values"];
NSString* myString = [myArray objectAtIndex:5];

그리고 다음 행을 따라 오류가 발생합니다.

[__NSDictionaryI objectAtIndex:] unrecognized selector sent to instance

에서 검색된 객체 myDictionary는 실제로 예상했던 NSArray가 아니라 NSDictionary 이기 때문 입니다.

불행히도 가장 혼란스러운 것은 이러한 종류의 오류가 자신의 코드가 아닌 UI 시스템 코드에서 발생하는 경우입니다. 이는 시스템 인터페이스에 잘못된 객체를 전달했거나 Interface Builder 또는 다른 곳에서 잘못된 클래스를 구성했을 때 발생할 수 있습니다.


답변

또 다른 가능한 이유는 원래 객체가 파괴 된 다음 다른 객체가 동일한 메모리 주소에 할당 되었기 때문입니다. 그런 다음 코드는 여전히 이전 개체에 대한 포인터가 있다고 생각하고 메시지를 보내고 새 개체가 해당 메시지를 이해하지 못하기 때문에 Objective-C에서 예외를 throw합니다.

이 문제를 진단하려면 ‘좀비’탐지 기능이있는 프로파일 러를 실행하십시오.


답변

스위프트 5.0

Introspection 을 사용 하여 개체가 특정 선택기에 응답하는지 여부를 확인할 수 있습니다 .

let canWork = yourObject.respondsToSelector(Selector("image"))   // true

코드가 작동하는 것이 사실 인 경우에만 .. 그렇지 않으면 확실히 충돌합니다.


답변

이 시나리오에서 두 가지를 살펴 보는 것이 도움이된다는 것을 알았습니다.

  1. 콜 스택
  2. 각 스택 프레임의 지역 변수 (및 해당 유형)

이 오류가 발생한 경우 일반적으로 유형 B를 예상 할 때 유형 A의 인스턴스에 메시지를 보냈기 때문입니다.

이 특정 시나리오에서는 상위 클래스의 요구 사항을 충족하지 못할 수 있습니다 (ItemTableViewCell의 인스턴스가 상속 할 가능성이 가장 높은 경우).

ItemTableViewCell 클래스에 대한 코드를 보여줄 수 있습니까?


답변

다음 코드를 사용하여 변수를 선언 할 수 있습니다.

let noteListTableViewCellobject = "NoteListTableViewCell";` `// Note listTablecell create custom cell`

func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {

    var cell:NoteListTableViewCell? = tableView.dequeueReusableCellWithIdentifier(noteListTableViewCellobject) as? NoteListTableViewCell

    if (cell == nil) {
        let nib:Array = NSBundle.mainBundle().loadNibNamed("NoteListTableViewCell", owner: self, options: nil)
        cell = nib[0] as? NoteListTableViewCell
    }
}