UITableView 作为 NIB 中的子视图的问题

Posted

技术标签:

【中文标题】UITableView 作为 NIB 中的子视图的问题【英文标题】:Problem with UITableView as subview in a NIB 【发布时间】:2010-11-21 19:10:02 【问题描述】:

执行摘要:我正在尝试使用UITableView 作为窗口“主”视图的子视图;它出现了,但是当我滚动窗口时,我收到以下错误消息:

2010-11-20 17:17:51.958 xwtf[6997:207] -[NSCFString tableView:cellForRowAtIndexPath:]: unrecognized selector sent to instance 0x5f46550

我有一个 ViewController 的子类,其中包含由我的应用程序委托加载的相应 NIB 文件。这是典型的新项目模板。在那个 NIB 文件中,我添加了一个 UITableView 作为视图的子视图。在 Interface Builder 中,我调整它的大小以占据整个窗口(即它完全覆盖其父视图)。

现在我需要指定一个数据源和委托。我创建了一个名为 DumbTableHelper 的类,如下所示:

@interface DumbTableHelper : NSObject<UITableViewDelegate, UITableViewDataSource> 

所以,它不是UIViewController 的子类,但我试图保持简单——我只需要一个可以调用的委托和数据源,对吧?除了dealloc,我在.m 文件中的方法是:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
  return 1;


- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section 
  return 10;


- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  static NSString *CellIdentifier = @"DumbTableCell";
  UITableViewCell *cell = [tableView
                           dequeueReusableCellWithIdentifier:CellIdentifier];
  if (cell == nil) 
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                     reuseIdentifier:CellIdentifier]
            autorelease];
  
  return cell;

如您所见,我什至没有配置任何单元格;我只指定了 10 行,这足以强制滚动。无论如何,在 Interface Builder 中,我将一个对象从库中拖到我的 NIB 中。然后我将其类名更改为DumbTableHelper,并将其指定为已经存在的UITableView 的数据源和委托。当我运行它时,表格出现了。当我尝试在表格中向下滚动时,我得到:

010-11-20 18:19:54.673 xwtf[6997:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString tableView:cellForRowAtIndexPath:]: unrecognized selector sent to instance 0x5f46550'
*** Call stack at first throw:
(
0   CoreFoundation                      0x0259eb99 __exceptionPreprocess + 185
1   libobjc.A.dylib                     0x0239340e objc_exception_throw + 47
2   CoreFoundation                      0x025a06ab -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3   CoreFoundation                      0x025102b6 ___forwarding___ + 966
4   CoreFoundation                      0x0250fe72 _CF_forwarding_prep_0 + 50
5   UIKit                               0x00321d6f -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:] + 619
6   UIKit                               0x00317e02 -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:] + 75
7   UIKit                               0x0032c69f -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow:] + 1348
8   UIKit                               0x003247ec -[UITableView layoutSubviews] + 242
9   QuartzCore                          0x0455c481 -[CALayer layoutSublayers] + 177
10  QuartzCore                          0x0455c1b1 CALayerLayoutIfNeeded + 220
11  QuartzCore                          0x045552e0 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 302
12  QuartzCore                          0x04555040 _ZN2CA11Transaction6commitEv + 292
13  QuartzCore                          0x04585ebb _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
14  CoreFoundation                      0x0257ff4b __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
15  CoreFoundation                      0x02514b27 __CFRunLoopDoObservers + 295
16  CoreFoundation                      0x024ddce7 __CFRunLoopRun + 1575
17  CoreFoundation                      0x024dd350 CFRunLoopRunSpecific + 208
18  CoreFoundation                      0x024dd271 CFRunLoopRunInMode + 97
19  GraphicsServices                    0x02d5d00c GSEventRunModal + 217
20  GraphicsServices                    0x02d5d0d1 GSEventRun + 115
21  UIKit                               0x002beaf2 UIApplicationMain + 1160
22  xwtf                                0x00001af4 main + 102
23  xwtf                                0x00001a85 start + 53
)

所以它在一个..字符串上调用tableView:cellForRowAtIndexPath:?有人有什么想法吗?

如果这是一个愚蠢的问题,我很抱歉——到目前为止,我所有的表视图都是由 UITableViewController 实例以编程方式创建的,但现在我需要添加一个 UITableView 作为子视图,这不会不要占据整个屏幕。我已阅读 Apple 关于表格视图和开始 iPhone 开发的指南,以确保我没有遗漏任何内容,但无济于事。

谢谢!

【问题讨论】:

我假设这与出现此错误时的问题相同:-[CALayer tableView:cellForRowAtIndexPath:]: unrecognized selector sent to instance 0x14563c90.. 即CALayer 而不是NSCFString(但我可以发誓我已经看到 NSCString 出现了之前遇到同样的问题).. 如果你也有CALayer,请鸣喇叭 【参考方案1】:

好的,我知道原因了:我的 ViewController 子类在我的 NIB 文件中也用作文件所有者,但没有声明到 DumbTableHelper 的出口。 http://developer.apple.com/library/mac/documentation/cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html 的 Nib 文件资源编程指南说:

nib 文件中的对象创建时保留计数为 1,然后自动释放...如果您为 nib 文件对象定义了 outlet,则应始终定义一个 setter 方法(或声明的属性)来访问该 outlet。 outlet 的 setter 方法应该保留它们的值,而包含***对象的 outlet 的 setter 方法必须保留它们的值,以防止它们被释放。

当表格第一次显示时,DumbTableHelperretainCount 仍然为 1 并且还没有被自动释放,所以它可以用来填充最初显示的行。但是,当我滚动时,它不再存在于内存中。从堆栈跟踪中,我们可以推测在DumbTableHelper曾经所在的内存地址中分配了一个字符串,因此它错误地接收到了tableView:cellForRowAtIndexPath:消息。

同样,只需将文件所有者的出口连接到 Interface Builder 文件中的 DumbTableHelper 实例即可解决问题。

【讨论】:

hum.. 这很有趣.. 但我有两个问题:1. 有人会认为这是一个应该通过使用 ARC 自动解决的问题(我从您的 alloc 释放引用中推断)这是非 ARC 代码).. 事情是我 am 使用 ARC 但我仍然遇到同样的问题 2. 在您的情况下,您可以简单地引用情节提要 b/c 中的数据源出口您的数据源是单一且已定义的.. 如果您使用在运行时定义的数据源(这就是我所做的.. 我使用具有不同数据源的相同 uitableviewcontroller/tableview)怎么办?你是怎么处理的?【参考方案2】:

我建议在 Interface Builder 中删除您的连接并尝试重新建立。看起来好像 dataSource 出口已经连接到 nib 中的 NSString。您也可以尝试使用 UITableView 的委托和数据源属性在代码中建立连接。

【讨论】:

感谢水晶骷髅的帮助!今天下午经过一番调查,我找到了原因。字符串实例是一个红鲱鱼,真的......有关详细信息,请参阅我的答案。

以上是关于UITableView 作为 NIB 中的子视图的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何将 nib 文件中的 UITableView 加载到父视图控制器中的容器视图中?

如何从 ViewController 中的 xib (nib) 实例化 UIView / UITableView

iOS 8 中 Nib 加载的子视图的位置不正确

如何显示从单独的 NIB 文件加载的子视图

tableView 作为半透明视图中的子视图

IOS:如何使从 nib 文件加载的子视图可以使用它的按钮(IBAction)