实例收到未识别的选择器

6
我得到了以下错误消息,我不知道为什么会出现这个错误,因为我没有使用任何UIImageView。有时我会收到相同的错误消息,但它是一个CALayer?值得一提的是,我有2个nib文件和2个控制器,还有一个基础控制器,代码位于其中。
编辑:
这是我的项目结构:
MainViewController及其nib文件 - 在nib中的HomeViewController MainViewController-Landscape和其nib文件 - 在nib中的HomeViewController-Landscape HomeViewControllerBase - 没有nib文件 - 所有输出和项配置代码都在此基类中。 - 输出由下面两个子类共用。 - 输出与每个主nib文件中的控件链接。
HomeViewController - 继承自HomeViewControllerBase HomeViewController-Landscape - 继承自HomeViewControllerBase 因此,子类正在尝试销毁其基类(其中包含所有输出)。 我设计成这样是为了避免在不同方向的视图控制器中重复代码。
@implementation MainViewController
- (void)orientationChanged:(NSNotification *)notification
{
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;

    if (UIDeviceOrientationIsLandscape(deviceOrientation) && !isShowingLandscapeView)
    {
        [self presentModalViewController:self.landscapeViewController
                                animated:YES];

        isShowingLandscapeView = YES;
    }
    else if (UIDeviceOrientationIsPortrait(deviceOrientation) && isShowingLandscapeView)
    {
        [self dismissModalViewControllerAnimated:YES];
        isShowingLandscapeView = NO;
    }
}

- (id)init
{
    self = [super initWithNibName:@"MainViewController" bundle:nil];

    if (self)
    {
        isShowingLandscapeView = NO;
        self.landscapeViewController = [[[MainViewController_Landscape alloc]
                                            initWithNibName:@"MainViewController-Landscape" bundle:nil] autorelease];

        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(orientationChanged:)
                                                     name:UIDeviceOrientationDidChangeNotification
                                                   object:nil];
    }

    return self;
}
@end

@implementation HomeViewControllerBase

    - (void)bestSellItemTapped:(id)sender
    {
        NSLog(@"best sell item tapped");
    }

    - (void)configureBestSellItems
    {
        [self startRetrievingRegions];

        // load all the images from our bundle and add them to the scroll view
        //  NSUInteger i;
        for (int i = 0; i <= 150; i++)
        {

            UILabel *itemTitle = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
            itemTitle.text = @"Majorca";

            UILabel *itemPrice = [[UILabel alloc]initWithFrame:CGRectMake(0, 50, 100, 50)];
            itemPrice.text = @"£249";

            NSString *imageName = @"tempImage.jpg";
            UIImage *image = [UIImage imageNamed:imageName];


            UIButton *mainButton = [[[UIButton alloc]init] autorelease];

            [mainButton addTarget:self action:@selector(bestSellItemTapped:) forControlEvents:UIControlEventTouchUpInside];
            [mainButton setBackgroundImage:image forState:UIControlStateNormal];



            // setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
            CGRect rect = mainButton.frame;
            rect.size.height = kScrollObjHeight;
            rect.size.width = kScrollObjWidth;

            mainButton.frame = rect;
            mainButton.tag = i;


            [mainButton addSubview:itemTitle]; [itemTitle release];
            [mainButton addSubview:itemPrice]; [itemPrice release];




            [self.bestSellScrollView addSubview:mainButton];


        }

        [self layoutScrollImages];  // now place the photos in serial layout within the scrollview
    }


    // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [self configureBestSellItems];
    }

    - (void)layoutScrollImages
    {
        UIButton *view = nil;
        NSArray *subviews = [self.bestSellScrollView subviews];

        // reposition all image subviews in a horizontal serial fashion
        CGFloat curXLoc = 0;
        for (view in subviews)
        {
            if ([view isKindOfClass:[UIButton class]] && view.tag > 0)
            {
                CGRect frame = view.frame;
                frame.origin = CGPointMake(curXLoc, 0);
                view.frame = frame;

                curXLoc += (kScrollObjWidth + kScrollObjPadding);
            }
        }

        // set the content size so it can be scrollable
        [self.bestSellScrollView setContentSize:CGSizeMake((150 * kScrollObjWidth), 
                                                           [self.bestSellScrollView bounds].size.height)];
    }

@end

@interface HomeViewController : HomeViewControllerBase
@end

@interface HomeViewController_Landscape : HomeViewControllerBase
@end

@implementation HomeViewController

- (void)dealloc
{
    [super dealloc]; //When I remove this it works
}

@end

@implementation HomeViewController_Landscape

- (void)dealloc
{
   [super dealloc]; //When I remove this it works
}

@end

-[UIImageView bestSellItemTapped:]: unrecognized selector sent to instance 0x681c2b0 2011-04-12 15:45:26.665 [21532:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImageView bestSellItemTapped:]: unrecognized selector sent to instance 0x681c2b0'
*** Call stack at first throw: (    0   CoreFoundation                      0x00dc85a9 __exceptionPreprocess + 185  1   libobjc.A.dylib                   0x00f1c313 objc_exception_throw + 44  2   CoreFoundation                    0x00dca0bb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187  3   CoreFoundation                      0x00d39966 ___forwarding___ + 966   4   CoreFoundation                      0x00d39522 _CF_forwarding_prep_0 + 50   5   UIKit                             0x0001a4fd -[UIApplication sendAction:to:from:forEvent:] + 119    6 UIKit                               0x000aa799 -[UIControl sendAction:to:forEvent:] + 67  7   UIKit                               0x000acc2b -[UIControl(Internal)
_sendActionsForEvents:withEvent:] + 527     8   UIKit                         0x000ab7d8 -[UIControl touchesEnded:withEvent:] + 458     9   UIKit                               0x002ad4de
_UIGestureRecognizerSortAndSendDelayedTouches
+ 3609  10  UIKit                               0x002adc53
_UIGestureRecognizerUpdateObserver + 927    11  CoreFoundation                0x00da989b
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
+ 27    12  CoreFoundation                      0x00d3e6e7 __CFRunLoopDoObservers + 295     13  CoreFoundation                0x00d071d7 __CFRunLoopRun + 1575  14  CoreFoundation                      0x00d06840 CFRunLoopRunSpecific + 208   15  CoreFoundation                    0x00d06761 CFRunLoopRunInMode + 97    16 GraphicsServices                    0x010001c4 GSEventRunModal + 217     17  GraphicsServices                    0x01000289 GSEventRun + 115     18  UIKit 0x00028c93 UIApplicationMain + 1160   19                      0x000027a9 main + 121   20 
                      0x00002725 start + 53 ) terminate called after throwing an instance of 'NSException'

1
我注意到的一件事是,在您创建151个按钮时,您使scrollview的contentSize变为150倍的某些内容。 - onnoweb
3个回答

2

当点击按钮时,这段代码中的ViewController是否还活着?类似于这种错误(与对象无关 - 在本例中为UIImageView)通常意味着你有一个指向已释放并为其他东西(在本例中为UIImageView)重用的内存区域的指针。

在视图控制器的-dealloc方法中添加一个NSLog()打印输出,并确保在单击按钮之前不会触发它。

实际上,在configureBestSellItems的开头再添加一个NSLog - NSLog(@"I am %x", self);(是的,%x而不是%@)。这将打印出你的视图控制器的地址 - 将其与崩溃对象的地址进行比较(如“未识别的选择符发送到实例0x681c2b0” - 看看它最初是否打印“I am 0x681c2b0”)。


@SVD - 我从子控制器中删除了[super dealloc],这似乎起作用了,但我不确定基础控制器是否会被释放!? - TheLearner
1
删除[super dealloc]是错误的做法。显然,您遇到了一个问题,即self控制器意外地被释放,但是通过删除[super dealloc],您只是掩盖了这个问题,而不是解决它。您应该发布更多与主视图控制器如何实例化和呈现相关的代码。那应该是问题所在。 - XJones
@TheLearner 移除 [super dealloc] 可以确认您在某个地方意外释放了对象,但这并不是解决方案。 - SVD
@SVD 如果你有其他问题,我在 iPhone/iPad 聊天室里,感谢你的帮助。 - TheLearner
好的,那么问题是在您切换到横屏时发生的吗?还是在您切换到横屏然后再切回来时发生的?您是否在横屏和竖屏视图之间共享bestSellScrollView?您可能需要在两个视图的dealloc方法中添加断点(或NSLog()),并查看它们是否在意外时刻被释放。 - SVD
显示剩余4条评论

1

如果您正在使用InterfaceBuilder,并将GUI元素连接/链接到控制器头文件中的IBActions /方法,请右键单击"cntrl + 单击"导致错误的GUI元素仅连接/链接到现有方法。

请参见{{link1:`向UIViewController发送dismissViewControllerAnimated:completion`后收到`未识别的选择器发送到实例<OBJ_ADR>`}}


0
当你分配你的UIButton时,你将其标记为autorelease,这可能是崩溃的原因,因为系统有可能会声明mainButton
UIButton *mainButton = [[[UIButton alloc]init] autorelease];

尝试移除autorelease,如果这样可以的话,将你的UIButton设为类变量或使用UIButtonbuttonWithType从系统获取按钮。


除了 CALayer 之外,去掉自动释放池后得到相同的错误。 - TheLearner
这不是问题所在。你需要释放 mainButton。你的自动释放是正确的。如果你将其移除,那么在将其添加到其父视图后,你需要显式释放 mainButton - XJones

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接