我想在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]
数组中找到了自己的位置。
但是,如果尝试将它们绑定到NSTextFieldCell
程序中的NSTableView
字体,则会爆炸:
(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所缺少的东西。但是呢?
答案 0 :(得分:0)
我没有找到答案。但是,由于在尝试使用NSPredicate时就开始了无限循环,因此在比较NSCTFont isEqual:
上,我为字体制作了一个控制器,并使用它们与NSPredicate进行比较。不再有无限循环。
答案 1 :(得分:0)
您没有做错任何事情。这是macOS中的错误。
您可以将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);
}
因此,如果对象没有明显不同(因为other
为nil)并且明显不同(因为它们是相同的指针),则此isEqual:
方法将调用{{1} },这是Core Foundation的私有功能。碰巧_CFNonObjCEqual
是Core Foundation开源版本的一部分,因此我们可以看看its implementation:
_CFNonObjCEqual
该注释告诉我们所期望的:Boolean _CFNonObjCEqual(CFTypeRef cf1, CFTypeRef cf2) {
//cf1 is guaranteed to be non-NULL and non-ObjC, cf2 is unknown
if (cf1 == cf2) return true;
if (NULL == cf2) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT; }
CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1);
CFTYPE_SWIFT_FUNCDISPATCH1(Boolean, cf2, NSObject.isEqual, (CFSwiftRef)cf1);
__CFGenericAssertIsCF(cf1);
__CFGenericAssertIsCF(cf2);
if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false;
if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) {
return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2);
}
return false;
}
参数必须是不是本机Objective-C实例的Core Foundation类型,但是cf1
参数可能是本机Objective-C实例。
重要的一行是这一行:
cf2
这是一个C宏,我们看不到它的真实定义,因为真实定义已从开源版本中删除。但是我们可以猜测,它可能会扩展为以下形式:
CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1);
如果if ([cf2 respondsToSelector:@selector(isEqual:)]) {
return [cf2 isEqual:cf1];
}
也是也是一个cf2
,这将是一个问题,因为它随后递归调用NSCTFont
(交换了参数),它将回呼到-[NSCTFont isEqual:]
的恶作剧中(直到您得到该网站命名的堆栈溢出信息为止)。
您可以在https://feedbackassistant.apple.com/上提交错误报告,或者根据需要使用“反馈助手”应用程序。