Search code examples
iosobjective-cuiimageviewnsarrayunrecognized-selector

Error when calling method to display am array of images in a UIImageView


I programmatically create a UIImageView within a method every 30 seconds and then start an NSTimer that will use that UIImageView to display an array of images for 5 seconds. When the method is called, however, the app crashes.

App lines:

-(void)CollectPoints{
    if(PlayTimer < 59){
        PlayTimer = PlayTimer + 1;
    }
    else{
        PlayTimer = 0;
        timeMinute+=1;
    }

    if(PlayTimer == 5 || (PlayTimer == 0 && timeMinute > 0)){
        bonusItemY = (575 - arc4random() % (515));
        bonusItemX = ((self.view.center.x + 20) + arc4random() % (80));
        UIImageView *bonusImg = [[UIImageView alloc] initWithFrame:CGRectMake(bonusItemX, bonusItemY, 50, 50)];
        bonusImg.image = [UIImage imageNamed:[bonusImgs objectAtIndex:bonusImgsNum]];
        //[self.view addSubview:bonusImg];
        bonusImgDraw = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(bonusItems) userInfo:bonusImg repeats:YES];
    }
}

-(void)bonusItems:(UIImageView*)bonusImg{
    if(bonusImgsNum < 1){
        bonusImgsNum+=1;
    }
    else{
        bonusImgsNum = 0;
    }
    bonusImg.image = [UIImage imageNamed:[bonusImgs objectAtIndex:bonusImgsNum]];
}

The error reads:

[ViewController2 bonusItems]: unrecognized selector sent to instance 0x7f9279620c80
2016-05-02 18:28:39.676 Jumping-Jinn[2220:140492] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController2 bonusItems]: unrecognized selector sent to instance 0x7f9279620c80'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000103b5cd85 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001032c3deb objc_exception_throw + 48
    2   CoreFoundation                      0x0000000103b65d3d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x0000000103aabcfa ___forwarding___ + 970
    4   CoreFoundation                      0x0000000103aab8a8 _CF_forwarding_prep_0 + 120
    5   Foundation                          0x0000000102eaa811 __NSFireTimer + 83
    6   CoreFoundation                      0x0000000103ab6074 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    7   CoreFoundation                      0x0000000103ab5c21 __CFRunLoopDoTimer + 1089
    8   CoreFoundation                      0x0000000103a77b11 __CFRunLoopRun + 1937
    9   CoreFoundation                      0x0000000103a770f8 CFRunLoopRunSpecific + 488
    10  GraphicsServices                    0x000000010863aad2 GSEventRunModal + 161
    11  UIKit                               0x00000001045daf09 UIApplicationMain + 171
    12  Jumping-Jinn                        0x0000000102db9a5f main + 111
    13  libdyld.dylib                       0x00000001069fe92d start + 1
    14  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

The failure line is the following:

bonusImg.image = [UIImage imageNamed:[bonusImgs objectAtIndex:bonusImgsNum]];

Solution

  • You have two problems.

    1. You are passing the wrong selector when creating the timer.
    2. The signature of your bonusItems: method is incorrect.

    When you create the timer, you need to use:

    bonusImgDraw = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(bonusItems:) userInfo:bonusImg repeats:YES];
    

    The only change is the addition of the colon in the method name passed inside @selector().

    And the method for a timer takes one parameter - the timer that triggered it. So your bonusItems: method needs to start with:

    -(void)bonusItems:(NSTimer *)timer {
    

    Since you want to get a reference to bonusImg, you are passing it as the timer's userInfo. You can get this inside the bonusItems: method through the timer's userInfo property. So your method becomes:

    -(void)bonusItems:(NSTimer *)timer {
        UIImageView *bonusImg = timer.userInfo;
    
        if (bonusImgsNum < 1) {
            bonusImgsNum+=1;
        } else {
            bonusImgsNum = 0;
        }
    
        bonusImg.image = [UIImage imageNamed:bonusImgs[bonusImgsNum]];
    }