我有一个Objective-C类SBUSBDevice
,它代表用户插入系统的USB驱动器。在我的一个视图控制器中,我获取包含这些对象的字典,将它们添加到数组中,并尝试使用此数组执行操作:
#import "SBUSBSetupWindowController.h"
#import "SBAppDelegate.h"
#import "SBUSBDevice.h"
@interface SBUSBSetupWindowController ()
@property (strong) NSDictionary *usbDictionary;
@property (weak) IBOutlet NSTableView *tableView;
@property (weak) IBOutlet NSButton *enableStartupDiskButton;
@property (strong) NSMutableArray *usbArray;
@end
@implementation SBUSBSetupWindowController
- (id)initWithWindow:(NSWindow *)window {
self = [super initWithWindow:window];
if (self) {
// Initialization code here.
self.usbDictionary = [[(SBAppDelegate *)[NSApp delegate] usbDictionary] copy];
self.usbArray = [[NSMutableArray alloc] initWithCapacity:[self.usbDictionary count]];
[self.usbDictionary enumerateKeysAndObjectsUsingBlock:^(id key, SBUSBDevice *object, BOOL *stop) {
NSLog(@"%@ = %@", key, object);
[self.usbArray addObject:object]; // <-- CRASH OCCURS HERE
}];
}
return self;
}
不幸的是,当我运行代码时,它会抛出以下异常:
[SBUSBDevice copyWithZone:]: unrecognized selector sent to instance 0x6080004602c0
据我所知,我不是要复制任何SBUSBDevice
个实例,因此不需要执行copyWithZone:
。我在我的应用程序的其他区域使用相同的技术,略有不同,它们都有效。为什么抛出这个异常?
以下是最初创建SBUSBDevice
个对象的方法。请注意,它们被放入字典中,稍后由上面的代码引用:
- (void)detectAndSetupUSBs {
if (!self.usbDictionary) {
self.usbDictionary = [[NSMutableDictionary alloc] initWithCapacity:10];
}
NSArray *volumes = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:0];
BOOL isRemovable, isWritable, isUnmountable;
NSString *description, *volumeType;
BOOL acceptHFSDrives = [[NSUserDefaults standardUserDefaults] boolForKey:@"AcceptHFSDrives"];
for (NSURL *mountURL in volumes) {
NSString *usbDeviceMountPoint = [mountURL path];
if ([[NSWorkspace sharedWorkspace] getFileSystemInfoForPath:usbDeviceMountPoint isRemovable:&isRemovable isWritable:&isWritable isUnmountable:&isUnmountable description:&description type:&volumeType]) {
if (isRemovable && isWritable && isUnmountable) {
NSLog(@"Detected eligible volume at %@. Type: %@", usbDeviceMountPoint, volumeType);
if ([usbDeviceMountPoint isEqualToString:@"/"]) {
// Don't include the root partition in the list of USBs.
continue;
}
else {
if ([volumeType isEqualToString:@"msdos"] ||
([volumeType isEqualToString:@"hfs"] && acceptHFSDrives)) {
SBUSBDevice *usbDevice = [[SBUSBDevice alloc] init];
usbDevice.path = usbDeviceMountPoint;
usbDevice.name = [usbDeviceMountPoint lastPathComponent];
[SBAppDelegate uuidForDeviceName:usbDeviceMountPoint];
self.usbDictionary[usbDevice.name] = usbDevice;
}
}
}
}
}
}
这是异常的文本(插入的每个USB驱动器都会发生一次):
2014-09-17 15:59:50.586 Mac Linux USB Loader[875:303] -[SBUSBDevice copyWithZone:]: unrecognized selector sent to instance 0x608000469140
2014-09-17 15:59:50.596 Mac Linux USB Loader[875:303] (
0 CoreFoundation 0x00007fff8de8725c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff85e2ae75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8de8a12d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x00007fff8dde5272 ___forwarding___ + 1010
4 CoreFoundation 0x00007fff8dde4df8 _CF_forwarding_prep_0 + 120
5 AppKit 0x00007fff8aa79186 -[NSCell _setContents:] + 74
6 AppKit 0x00007fff8aa95f5c -[NSCell setObjectValue:] + 317
7 AppKit 0x00007fff8aa95c8e -[NSTextFieldCell setObjectValue:] + 91
8 AppKit 0x00007fff8ad13df6 -[NSTableView preparedCellAtColumn:row:] + 589
9 AppKit 0x00007fff8ad13a5e -[NSTableView _drawContentsAtRow:column:withCellFrame:] + 44
10 AppKit 0x00007fff8ad13793 -[NSTableView drawRow:clipRect:] + 1629
11 AppKit 0x00007fff8ad12fed -[NSTableView drawRowIndexes:clipRect:] + 776
12 AppKit 0x00007fff8abdc331 -[NSTableView drawRect:] + 1484
13 AppKit 0x00007fff8abb7557 -[NSView(NSInternal) _recursive:displayRectIgnoringOpacity:inGraphicsContext:CGContext:topView:shouldChangeFontReferenceColor:] + 1082
14 AppKit 0x00007fff8abb700d __46-[NSView(NSLayerKitGlue) drawLayer:inContext:]_block_invoke + 186
15 AppKit 0x00007fff8abb6e03 -[NSView(NSLayerKitGlue) _drawViewBackingLayer:inContext:drawingHandler:] + 2297
16 AppKit 0x00007fff8abb64f8 -[NSView(NSLayerKitGlue) drawLayer:inContext:] + 108
17 QuartzCore 0x00007fff8cb46812 CABackingStoreUpdate_ + 2220
18 QuartzCore 0x00007fff8cb45f60 ___ZN2CA5Layer8display_Ev_block_invoke + 59
19 QuartzCore 0x00007fff8cb45f1c x_blame_allocations + 84
20 QuartzCore 0x00007fff8cb45a2b _ZN2CA5Layer8display_Ev + 1539
21 AppKit 0x00007fff8abb63c3 _NSBackingLayerDisplay + 235
22 AppKit 0x00007fff8ab8d74b -[_NSViewBackingLayer display] + 811
23 QuartzCore 0x00007fff8cb45162 _ZN2CA5Layer17display_if_neededEPNS_11TransactionE + 590
24 QuartzCore 0x00007fff8cb448b1 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 35
25 QuartzCore 0x00007fff8cb4433c _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 236
26 QuartzCore 0x00007fff8cb43fd6 _ZN2CA11Transaction6commitEv + 388
27 QuartzCore 0x00007fff8cb54761 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 71
28 CoreFoundation 0x00007fff8ddb7d67 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
29 CoreFoundation 0x00007fff8ddb7cd7 __CFRunLoopDoObservers + 391
30 CoreFoundation 0x00007fff8dda8e94 CFRunLoopRunSpecific + 340
31 HIToolbox 0x00007fff8b725a0d RunCurrentEventLoopInMode + 226
32 HIToolbox 0x00007fff8b7257b7 ReceiveNextEventCommon + 479
33 HIToolbox 0x00007fff8b7255bc _BlockUntilNextEventMatchingListInModeWithFilter + 65
34 AppKit 0x00007fff8aa5624e _DPSNextEvent + 1434
35 AppKit 0x00007fff8aa5589b -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
36 AppKit 0x00007fff8aa4999c -[NSApplication run] + 553
37 AppKit 0x00007fff8aa34783 NSApplicationMain + 940
38 Mac Linux USB Loader 0x000000010001c432 main + 34
39 libdyld.dylib 0x00007fff83b445fd start + 1
)
我已经尝试过我所想过的一切,但是,我在Objective-C上基本上是自学成才,我担心我可能会遗漏一些东西。如果您需要任何其他源代码,请随时询问。
答案 0 :(得分:1)
您正在cellForRowAtIndexPath中引用您的usbArray来填充单元格,并且您将SBUSBDevice指针直接粘贴到某处的单元格显示结构中。可能你打算使用SBUSBDevice对象的一些属性(例如,NSString)。
答案 1 :(得分:0)
我想我明白发生了什么。
您发送给usbDictionary的复制邮件会向每个内容发送一条复制邮件(这对于几乎所有收集项都是典型的)。
因此,复制消息被发送到SBUSBDevice对象(存储在字典中),从而导致异常。
看看附带的代码片段,我想不出我们为什么在这里复制的原因。将对象添加到集合应该会自动增加保留计数。
答案 2 :(得分:0)
我相对肯定是这一行:
self.usbDictionary = [[(SBAppDelegate *)[NSApp delegate] usbDictionary] copy];
如果您尝试复制包含未实现复制协议的对象的字典,则会崩溃。你确定崩溃发生在你认为它发生的地方,而不是在这条线上吗?