UIMenuController 在重用单元格时使应用程序崩溃

Posted

技术标签:

【中文标题】UIMenuController 在重用单元格时使应用程序崩溃【英文标题】:UIMenuController crashes application when cell is reused 【发布时间】:2014-03-14 11:31:16 【问题描述】:

我是使用 UIMenuController 的新手。我在 UITableViewCell 的长按手势上做了一个 UIMenuController。它运行良好,直到细胞不被重复使用。当我滚动表格视图并重用单元格时,长按单元格崩溃应用程序。错误显示在线 - [cell becomeFirstResponder]。

我的代码是-

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
    
    // Standard bubble

    NSBubbleData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
    static NSString *cellId1 = @"tblBubbleCell";
    UIBubbleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId1];
    if (cell == nil) cell = [[UIBubbleTableViewCell alloc] init];
    cell.data = data;
    cell.key=data.key;
    cell.showAvatar = self.showAvatars;

    UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
    [cell addGestureRecognizer:recognizer];
    return cell;



#pragma mark - Menu controller

- (void)longPress:(UILongPressGestureRecognizer *)recognizer 
if (recognizer.state == UIGestureRecognizerStateBegan) 
       UIBubbleTableViewCell *referenceCell = (UIBubbleTableViewCell *)recognizer.view;
       [referenceCell becomeFirstResponder];//error line when cell is reused and long  pressed

   UIMenuItem *forward = [[UIMenuItem alloc] initWithTitle:@"Forward" action:@selector(forward:)];

    UIMenuController *menu = [UIMenuController sharedMenuController];
    [menu setMenuItems:[NSArray arrayWithObjects:forward, nil]];
    [menu setTargetRect:referenceCell.frame inView:referenceCell.superview];
    [menu setMenuVisible:YES animated:YES];



- (void)copy:(id)sender 
    NSLog(@"Cell is copied");
    

- (void)delete:(id)sender 

    

- (void)forward:(id)sender 
    NSLog(@"Cell forwarded");
   

我曾一度陷入这个问题。请帮忙。

UIBubbleTableViewCell 里面的代码是->

@implementation UIBubbleTableViewCell

@synthesize data = _data;
@synthesize customView = _customView;
@synthesize bubbleImage = _bubbleImage;
@synthesize showAvatar = _showAvatar;
@synthesize avatarImage = _avatarImage;
@synthesize userName=_userName;
@synthesize key=_key;

- (BOOL)canBecomeFirstResponder 
   return YES;


- (void)setFrame:(CGRect)frame

    [super setFrame:frame];
[self setupInternalData];


#if !__has_feature(objc_arc)
- (void) dealloc

  self.data = nil;
  self.customView = nil;
  self.bubbleImage = nil;
  self.avatarImage = nil;
  [super dealloc];

#endif

- (void)setDataInternal:(NSBubbleData *)value

self.data = value;
[self setupInternalData];


- (void) setupInternalData

   self.selectionStyle = UITableViewCellSelectionStyleNone;

   if (!self.bubbleImage)
   
   #if !__has_feature(objc_arc)
    self.bubbleImage = [[[UIImageView alloc] init] autorelease];
   #else
    self.bubbleImage = [[UIImageView alloc] init];        
   #endif
    [self addSubview:self.bubbleImage];
   

   NSBubbleType type = self.data.type;

   CGFloat width = self.data.view.frame.size.width;
   CGFloat height = self.data.view.frame.size.height;

   CGFloat x = (type == BubbleTypeSomeoneElse) ? 0 : self.frame.size.width - width -   self.data.insets.left - self.data.insets.right;
   CGFloat y = 0;

   // Adjusting the x coordinate for avatar
   if (self.showAvatar)
    
    [self.avatarImage removeFromSuperview];
    #if !__has_feature(objc_arc)
    self.avatarImage = [[[UIImageView alloc] initWithImage:(self.data.avatar ?      self.data.avatar : [UIImage imageNamed:@"missingAvatar.png"])] autorelease];
    #else
    self.avatarImage = [[UIImageView alloc] initWithImage:(self.data.avatar ?   self.data.avatar : [UIImage imageNamed:@"missingAvatar.png"])];
    #endif
    self.avatarImage.layer.cornerRadius = 9.0;
    self.avatarImage.layer.masksToBounds = YES;
    self.avatarImage.layer.borderColor = [UIColor colorWithWhite:0.0 alpha:0.2].CGColor;
    self.avatarImage.layer.borderWidth = 1.0;

    CGFloat avatarX = (type == BubbleTypeSomeoneElse) ? 2 : self.frame.size.width - 52;
    CGFloat avatarY = self.frame.size.height - 50;

    self.avatarImage.frame = CGRectMake(avatarX, avatarY, 50, 50);
    [self addSubview:self.avatarImage];

    CGFloat delta = self.frame.size.height - (self.data.insets.top + self.data.insets.bottom + self.data.view.frame.size.height);
    if (delta > 0) y = delta;

    if (type == BubbleTypeSomeoneElse) x += 54;
    if (type == BubbleTypeMine) x -= 54;


[self.customView removeFromSuperview];
self.customView = self.data.view;
self.customView.frame = CGRectMake(x + self.data.insets.left, y +     self.data.insets.top, width, height);
[self.contentView addSubview:self.customView];

if (type == BubbleTypeSomeoneElse)

    self.bubbleImage.image = [[UIImage imageNamed:@"bubbleSomeone.png"] stretchableImageWithLeftCapWidth:21 topCapHeight:14];


else 
    self.bubbleImage.image = [[UIImage imageNamed:@"bubbleMine.png"] stretchableImageWithLeftCapWidth:15 topCapHeight:14];

self.bubbleImage.frame = CGRectMake(x, y, width + self.data.insets.left +   self.data.insets.right, height + self.data.insets.top + self.data.insets.bottom);




@end

【问题讨论】:

在这种情况下你遇到了什么错误?? 没有显示任何错误,应用程序只是崩溃表明该行 - [referenceCell becomeFirstResponder] 只有当我长按一个单元格然后滚动表格视图并长按其他单元格时才会出现此错误。 我试过你的代码。但它没有崩溃。唯一的区别是我尝试使用 UIBubbleTableViewCell 的 UITableViewCell UIBubbleTableViewCell 包含什么。表示您在其上添加的子视图。 【参考方案1】:

试试这个:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
    
    // Standard bubble

    NSBubbleData *data = [[self.bubbleSection objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
    static NSString *cellId1 = @"tblBubbleCell";
    UIBubbleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId1];
    if (cell == nil) 
        cell = [[UIBubbleTableViewCell alloc] init];
        UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
        [cell addGestureRecognizer:recognizer];
    

    cell.data = data;
    cell.key=data.key;
    cell.showAvatar = self.showAvatars;

    return cell;

我不知道这是否会导致您的问题,但您只需将手势识别器添加到每个单元格一次。此外,您可能应该在您的单元子类中使用initWithStyle:

【讨论】:

这并不能解决我的问题。好的,现在我将使用 initWithStyle: 并让你知道。 能否在您的代码中添加 UIBubbleTableViewCell.h 文件,以便我们尝试调查原因 谢谢,在放置 cell = [[UIBubbleTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId1]; 后它现在可以工作了;

以上是关于UIMenuController 在重用单元格时使应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

为啥在制作自定义表格视图单元格时将可重用单元格出列两次

Swift - uitableview 重用单元格时用户输入混淆?

在添加 LinkPresentation 视图的堆栈上重用单元格时不显示元素

重用 UICollectionView 中的单元格时,会短暂显示重用 UICollectionViewCell 的旧内容

在 UITableViewCell 中显示 UIMenuController,分组样式

重用自定义 tableView 单元格时重复显示相同的子视图(Swift 4.1)