首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSFont和CTFont之间有什么区别?为什么CTFont会挂起NSTextFieldCell?

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

Stack Overflow用户
提问于 2019-06-11 18:34:31
回答 2查看 333关注 0票数 0

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

代码语言:javascript
复制
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字体会发生爆炸:

代码语言:javascript
复制
(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 ()
......
......

但是什么呢?

EN

回答 2

Stack Overflow用户

发布于 2019-07-11 05:27:24

你没做错什么。这是macOS中的一个错误。

您可以将CTFont转换为NSFont,因为这些类型是“免费桥接的”。这意味着CTFont在内存中的布局方式与Objective-C实例的要求相匹配。这些要求之一是对象的第一个字包含指向对象类的指针(称为“isa”指针)。对于CTFont,该类被命名为NSCTFont,并且它是NSFont的子类。

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

代码语言:javascript
复制
- (BOOL)isEqual:(NSObject *)other {
    if (other == 0) { return NO; }
    if (other == self) { return YES; }
    return _CFNonObjCEqual(self, other);
}

因此,如果对象没有明显的不同(因为other为nil),也没有明显的相同(因为它们是相同的指针),那么这个isEqual:方法将调用_CFNonObjCEqual,这是一个私有的核心基础函数。碰巧_CFNonObjCEqual是Core Foundation开放源码版本的一部分,所以我们可以看看its implementation

Boolean _CFNonObjCEqual(CFTypeRef cf1,CFTypeRef cf2) { //cf1保证为非空和非ObjC,如果(cf1 == cf2)返回true,则cf2未知;if (NULL == cf2) {CRSetCrashLogMessage(“* CFEqual()用NULL第二个参数调用*”);HALT;} CFTYPE_OBJC_FUNCDISPATCH1(Boolean,cf2,isEqual:,cf1);CFTYPE_SWIFT_FUNCDISPATCH1(Boolean,());();NULL( cf2);if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false;if (NULL != __CFGenericAssertIsCF{ return __CFRuntimeClassTable__CFGenericTypeID_inline(cf1)->equal(cf1,cf2);} return false;}

注释告诉我们应该做什么:必须知道cf1参数是核心基础类型,而不是本地Objective-C实例,但cf2参数可能是本地Objective-C实例。

重要的是这一行:

CFTYPE\_OBJC\_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1);

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

代码语言:javascript
复制
if ([cf2 respondsToSelector:@selector(isEqual:)]) {
    return [cf2 isEqual:cf1];
}

如果cf2是 an NSCTFont,这将是一个问题,因为它递归地调用-[NSCTFont isEqual:] (交换了参数),这将回调到_CFNonObjCEqual,ad nauseum (直到你得到这个网站命名的那种堆栈溢出)。

如果你愿意,你可以在https://feedbackassistant.apple.com/上提交一个错误报告,或者使用反馈助手应用程序。

票数 1
EN

Stack Overflow用户

发布于 2019-07-11 04:35:21

我没有找到答案。但是因为当我尝试使用NSPredicate时,无限循环开始了,所以在比较NSCTFont isEqual:时,我做了一个字体控制器,并使用它们通过NSPredicate进行比较。不再有无限循环。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56541788

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档