Swift NSFont和CTFont之间有什么区别?为什么CTFont会挂起NSTextFieldCell?

Swift NSFont和CTFont之间有什么区别?为什么CTFont会挂起NSTextFieldCell?,swift,core-text,nsfont,ctfont,ctfontref,Swift,Core Text,Nsfont,Ctfont,Ctfontref,我想在NSTableView中显示字体。如果我使用由NSFont(name:fontName,size:size)初始化的字体。但在这种情况下,我只能使用系统中安装的字体。所以我做了一个NSFont扩展: public extension NSFont { static func read(from path: String, size: CGFloat) throws -> NSFont { guard let dataProvider = CGDataProvi

我想在NSTableView中显示字体。如果我使用由
NSFont(name:fontName,size:size)初始化的字体
。但在这种情况下,我只能使用系统中安装的字体。所以我做了一个NSFont扩展:

public extension NSFont {
    static func read(from path: String, size: CGFloat) throws -> NSFont {
        guard let dataProvider = CGDataProvider(filename: path) else {
            throw NSError(domain: "file not found", code: 77, userInfo: ["fileName" : path])
        }
        guard let fontRef = CGFont ( dataProvider ) else {
            throw NSError(domain: "Not a font file", code: 77, userInfo: ["fileName" : path])
        }
        return CTFontCreateWithGraphicsFont(fontRef, size, nil, nil) as NSFont
    }
}
这似乎是可行的,用这种方法制作的字体在
[NSFont]
数组中找到了它们的位置。 但是,如果尝试将它们绑定到
NSTableView
程序中的
NSTextFieldCell
font,程序将爆炸:

(this goes forever and throws Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffeef3ffff8))
......
......
#261509 0x00007fff6c023e63 in -[NSCTFont isEqual:] ()
#261510 0x00007fff4539908c in _CFNonObjCEqual ()
#261511 0x00007fff6c023e63 in -[NSCTFont isEqual:] ()
#261512 0x00007fff4539908c in _CFNonObjCEqual ()
#261513 0x00007fff6c023e63 in -[NSCTFont isEqual:] ()
#261514 0x00007fff6bfccf63 in -[NSAttributeDictionary isEqualToDictionary:] ()
#261515 0x00007fff6bfccc11 in attributeDictionaryIsEqual ()
#261516 0x00007fff475c6712 in hashProbe ()
#261517 0x00007fff475c6518 in -[NSConcreteHashTable getItem:] ()
#261518 0x00007fff6bfc5be8 in +[NSAttributeDictionary newWithDictionary:] ()
#261519 0x00007fff6bff7cbe in -[_NSCachedAttributedString initWithString:attributes:] ()
#261520 0x00007fff6bfdac1f in __NSStringDrawingEngine ()
#261521 0x00007fff6bff7380 in _NSStringDrawingCore ()
#261522 0x00007fff42b16477 in _NSDrawTextCell2 ()
#261523 0x00007fff42b15328 in __45-[NSTextFieldCell _drawForegroundOfTextLayer]_block_invoke ()
#261524 0x00007fff42a8c529 in -[NSFocusStack performWithFocusView:inWindow:usingBlock:] ()
#261525 0x00007fff42b14bff in -[NSTextFieldCell _drawForegroundOfTextLayer] ()
#261526 0x00007fff42b1445a in -[NSTextFieldCell updateLayerWithFrame:inView:] ()
#261527 0x00007fff42b14322 in -[NSControl updateLayer] ()
#261528 0x00007fff42afe301 in _NSViewUpdateLayer ()
......
......

我认为CTFont中缺少NSFont所拥有的东西。但是什么?我没有找到答案。但由于无限循环是在我尝试使用NSPredicate时开始的,所以在比较
NSCTFont isEqual:
时,我为字体创建了一个控制器,并使用它们来通过NSPredicate进行比较。不再有无限循环。

你没有做错任何事。这是macOS中的一个bug

您可以将
CTFont
强制转换为
NSFont
,因为这些类型是“免费桥接”的。这意味着
CTFont
以符合Objective-C实例要求的方式排列在内存中。其中一个要求是对象的第一个单词包含指向对象类的指针(称为“isa”指针)。对于
CTFont
,该类被命名为
NSCTFont
,它是
NSFont
的子类

NSCTFont
(在UIFoundation私有框架中定义)重写
isEqual:
方法。如果您查看该函数的反汇编(如果您了解x86汇编),您将看到它的定义大致如下:

- (BOOL)isEqual:(NSObject *)other {
    if (other == 0) { return NO; }
    if (other == self) { return YES; }
    return _CFNonObjCEqual(self, other);
}
if ([cf2 respondsToSelector:@selector(isEqual:)]) {
    return [cf2 isEqual:cf1];
}

这样,如果对象没有明显不同(因为<代码>其他< /代码>是NIL),并且不是明显相同(因为它们是相同的指针),那么这个<代码>等于:方法调用<代码> ycFunObjultAsdie<代码>,这是一个私有核心基础函数。碰巧,<>代码> yfcObjbObjials是核心基础的开源版本的一部分,所以我们可以看看:

注释告诉我们预期:<代码> CF1参数必须是一个核心基础类型,它不是原生ObjuleC实例,但是 CF2参数可能是原生ObjuleC实例。

重要的是这条线:

这是一个C宏,我们看不到它的真正定义,因为真正的定义已经从开源版本中删除了。但我们可以猜测,它可能会扩展到这样的情况:

- (BOOL)isEqual:(NSObject *)other {
    if (other == 0) { return NO; }
    if (other == self) { return YES; }
    return _CFNonObjCEqual(self, other);
}
if ([cf2 respondsToSelector:@selector(isEqual:)]) {
    return [cf2 isEqual:cf1];
}
如果
cf2
也是一个
NSCTFont
,那么这将是一个问题,因为它递归调用
-[NSCTFont isEqual:
(参数交换),这将调用
\u CFNonObjCEqual
,这是一个非常奇怪的问题(直到获得此网站命名的堆栈溢出类型)


如果愿意,您可以在或使用反馈助手应用程序提交错误报告。

您绑定了什么?绑定到NSTableView中NSTextFieldCell的
font
绑定。如果表视图基于视图,则绑定
NSTextField
的字体。您绑定了什么字体?我选中了:NSTableView内容和索引绑定到
NSArrayController.arrangedObjects
。将对象设置为NSFont的SelectionIndex
。NSTableCell内的NSTextField绑定到:
value
objectValue.fontName
font
objectValue
。我认为绑定没有问题:有时我可以看到加载到表中的字体,它们看起来很像很好。但几秒钟后,鼠标点击程序挂起,并以无限循环结束。谢谢你这么清楚和深刻的解释。