64位模式下的objc_setAssociatedObject函数错误不在32位

ton*_*ack 8 64-bit 32-bit objective-c ios general-protection-fault

我在我的项目中使用一个名为SKSTableView的整洁的表视图控制器,它允许每个表行具有多个子行.这段代码在32位模式下运行完美,但是当我在iPhone 5S或4英寸64位模式的模拟器中运行时,当你点击一行来获取子行时它会崩溃.我对64位和32位iOS系统的差异一无所知.我很想知道这里发生了什么.

您会注意到*SubRowObjectKey设置为void-我得到的错误是: EXC_BAD_ACCESS_(code = EXC_I386_GPFLT)
这是一个一般保护错误,试图访问不存在的东西(?)

当它崩溃Xcode突出显示这行代码时
__CODE__:

#pragma mark - NSIndexPath (SKSTableView)
static void *SubRowObjectKey;
@implementation NSIndexPath (SKSTableView)
@dynamic subRow;
- (NSInteger)subRow
{
    id subRowObj = objc_getAssociatedObject(self, SubRowObjectKey);
    return [subRowObj integerValue];
}
- (void)setSubRow:(NSInteger)subRow
{
    if (IsEmpty(@(subRow))) {
        return;
    }
    id subRowObj = @(subRow);
    objc_setAssociatedObject(self, SubRowObjectKey, subRowObj, OBJC_ASSOCIATION_ASSIGN);
}
+ (NSIndexPath *)indexPathForSubRow:(NSInteger)subrow inRow:(NSInteger)row inSection:(NSInteger)section
{
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
    indexPath.subRow = subrow;   
    return indexPath;
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

Mar*_*n R 13

它似乎objc_setAssociatedObject()不适用于"标记指针".标记指针是不特殊指针指向的东西,但"价值"被存储在(某些位)指针本身.请参阅Objective-C中的标记指针,其中包含指向更多信息的链接.

标记指针仅与64位代码一起使用,例如,对于具有小行和段号的索引路径,或小数目对象.

可以很容易地验证在标记指针上设置关联对象与iOS 7/64位上的EXC_BAD_ACCESS崩溃:

static void *key = &key;

id obj = [NSIndexPath indexPathForRow:1 inSection:1];
objc_setAssociatedObject(obj, key, @"345", OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// --> EXC_BAD_ACCESS_(code=EXC_I386_GPFLT) 
Run Code Online (Sandbox Code Playgroud)

同样的事情发生在

id obj = @1;
id obj = [NSDate dateWithTimeIntervalSinceReferenceDate:0];
Run Code Online (Sandbox Code Playgroud)

它们也是64位模式下的标记指针.

我找不到任何有关此限制的文档,并认为这是iOS中的错误.此处报告了类似的问题:https://github.com/EmbeddedSources/iAsync/issues/22.我认为值得向Apple提交错误报告.

(注:OS X/64位上不会出现此问题.)


更新(可能的解决方案/解决方法): "SKSTableView"项目(问题末尾的链接)使用类别 NSIndexPath和关联对象将第三个属性"subrow"添加到索引路径.此子目录暂时设置

tableView:cellForRowAtIndexPath:
Run Code Online (Sandbox Code Playgroud)

SKSTableView通过当前子行到

tableView:cellForSubRowAtIndexPath:indexPath
Run Code Online (Sandbox Code Playgroud)

ViewController类中委托方法.

如果您使用"正确的"三级索引路径,则不需要关联对象,示例应用程序也以64位模式运行.

我对示例项目进行了以下更改:

SKSTableView.m中:

+ (NSIndexPath *)indexPathForSubRow:(NSInteger)subrow inRow:(NSInteger)row inSection:(NSInteger)section
{
    // Change:
    //NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
    //indexPath.subRow = subrow;
    // To:
    NSUInteger indexes[] = { section, row, subrow };
    NSIndexPath *indexPath = [NSIndexPath indexPathWithIndexes:indexes length:3];

    return indexPath;
}
Run Code Online (Sandbox Code Playgroud)

属性访问器方法

- (NSInteger)subRow;
- (void)setSubRow:(NSInteger)subRow;
Run Code Online (Sandbox Code Playgroud)

不再需要了.

ViewController.m中:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForSubRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"UITableViewCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (!cell)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

    // Change:
    //cell.textLabel.text = [NSString stringWithFormat:@"%@", self.contents[indexPath.section][indexPath.row][indexPath.subRow]];
    // To:
    cell.textLabel.text = [NSString stringWithFormat:@"%@", self.contents[[indexPath indexAtPosition:0]][[indexPath indexAtPosition:1]][[indexPath indexAtPosition:2]]];

    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    return cell;
}
Run Code Online (Sandbox Code Playgroud)


Tir*_*lan 5

更改以下方法中的设置:

- (NSInteger)subRow;
- (void)setSubRow:(NSInteger)subRow;

- (NSInteger)subRow
{
    id myclass = [SKSTableView class];

    id subRowObj = objc_getAssociatedObject(myclass, SubRowObjectKey);
    return [subRowObj integerValue];
}

- (void)setSubRow:(NSInteger)subRow
{
    id subRowObj = [NSNumber numberWithInteger:subRow];
    id myclass = [SKSTableView class];
    objc_setAssociatedObject(myclass, nil, subRowObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
Run Code Online (Sandbox Code Playgroud)

特别感谢@tufnica,网址https://github.com/sakkaras/SKSTableView/issues/2