2012-08-03 128 views
2

我刚开始使用苹果的编程GUI(到目前为止框架看起来不错,但我发现文档比其他人的信息要少得多...... Qt,.Net,Java等)。CTLineRef是否拥有属性字符串?

我遇到的其中一个问题就是了解谁拥有什么。例如,如果我调用CTLineRefCreateWithAttributedString,那么生成的CTLineRef是否拥有属性字符串?如果属性字符串是可变的,我会改变它?这会搞砸CTLineRef吗?

该文档一直没有提及。

为CTLineRef参考提供了关于这个问题的任何信息: https://developer.apple.com/library/mac/#documentation/Carbon/Reference/CTLineRef/Reference/reference.html

一些例子不释放字符串,我需要作为一个指标,它是拥有: https://developer.apple.com/library/mac/#documentation/StringsTextFonts/Conceptual/CoreText_Programming/Operations/Operations.html

一些例子做释放字符串,这将表明它不是: https://developer.apple.com/library/mac/#samplecode/CoreAnimationText/Listings/VectorTextLayer_m.html

(这个人是不是苹果,但他似乎更告诉他们我) http://www.cocoanetics.com/2011/01/befriending-core-text/

那么字符串是否被复制?如果我使用CFMutableAttributedStringRef我可以改变或不改变(我假设我将不得不创建一个新的CTLineRef之后)?

这是一个具体的例子,但这是我在无数的地方遇到的问题。任何帮助将非常感激。我觉得必须有一些规则来管理这些事情,但我丝毫不了解这些规则是什么,或者我能在哪里找到它们。

回答

4

您寻求的管理规则可在Core Foundation Memory Management Guide中找到。要带走的要点是,您实际上不需要知道CTLineRef是否拥有属性字符串。任何对象都可以有多个所有者。所有你需要担心的是你自己的字符串,以及在哪里最合适的地方放弃所有权是。如果您在创建CTLineRef后完成了该操作,则可以随意释放它。

考虑其余的CTLineRef的实现细节。如果CTLineRef遵循该文档中规定的规则并且需要保留属性字符串,它将在内部保留它。它也有可能在内部制作副本(这很可能),因此不再关心原始内容。也许它会将字符串发送到火星上的服务器,并在每次需要它时查询它(不太可能)。重要的一点是,不管它做什么,你都可以安全地释放字符串,如果你不再需要它。

至于可变性和复制行为,这有点模糊。你说得对,文件不明确的行为。文档明确表示该对象是不可变的。这意味着它几乎保证它确实实际上复制输入字符串(或将其内容解析为其他内容)。通常理解的最佳实践是,对象应始终根据您提到的确切原因制作输入字符串的副本 - 即实现无法知道提供的字符串是否实际上是可变的。为了保持执行力,它需要确保其内部状态不能从外部世界改变。做出这种保证的唯一方法是复制字符串。甚至可变类也是如此,CTLineRef不是。

+0

感谢您的信息,这真的很有帮助。 – user1574591 2012-08-03 16:41:20

+0

我阅读了链接的文档,但我仍然有点挂断电话。你说CTLineRef创建函数必须保留字符串并且可以复制它,但是它确实影响了我如何处理它。如果它保留它,那么我不应该修改任何可变字符串。而如果它复制它,那么我可以修改一个可变字符串。你发布的链接表明它“可能”是一个属性,“应该”做一个副本,我是否假设CTLineRef做到了这一点,并希望最好?我希望我有一份在这个问题上100%可靠的文件。 – user1574591 2012-08-03 16:53:18

+0

你在这一点上是正确的。我只是说它“很可能会复制”,因为我不知道这个实现是否真的将CFStringRef复制并存储为ivar。它也可能解析输入字符串并在某些其他数据结构中存储某些信息。如果复制语义没有用文字副本实现,则可以保证复制语义。它必须这样才能保证强大的实施。 – 2012-08-03 16:59:24

0

要回答您的问题,我们可以尝试在创建CTLine之前和之后查看字符串的引用计数。我们也可以尝试在更改字符串之前和之后打印行的描述。

CFMutableAttributedStringRef mas = CFAttributedStringCreateMutable(NULL, 0); 
CFAttributedStringReplaceString(mas, CFRangeMake(0, 0), CFSTR("world")); 
CTLineRef line = CTLineCreateWithAttributedString(mas); 
NSLog(@"mas count = %ld", CFGetRetainCount(mas)); 
NSLog(@"line before change = %@", line); 
CFAttributedStringReplaceString(mas, CFRangeMake(0, 0), CFSTR("hello ")); 
NSLog(@"line after change = %@", line); 

这往往徒劳无功看对象的保留计数,但在这种情况下,它的信息:

2012-08-03 12:11:10.717 coretext[44780:f803] count before creating line = 1 
2012-08-03 12:11:10.720 coretext[44780:f803] count after creating line = 1 

由于保留数为1的前后,而我自己的引用(因为CFAttributedStringCreateMutable给我一个拥有参考),我知道我是字符串的唯一所有者,在创建CTLine之前和之后。所以CTLine不保留字符串。这是不太可能的,它保留一个参考字符串,而不保留它。

这里的改变串前行的描述:

2012-08-03 12:11:10.721 coretext[44780:f803] line = CTLine: run count = 1, string range = (0, 5), width = 28.6758, A/D/L = 9.24023/2.75977/0, glyph count = 5 
{ 
    CTRun: string range = (0, 5), characters = { 0x0077, 0x006f, 0x0072, 0x006c, 0x0064 }, attributes = 
<CFBasicHash 0x6d69ce0 [0x1227b38]>{type = mutable dict, count = 1, 
entries => 
    2 : <CFString 0xab1b0 [0x1227b38]>{contents = "NSFont"} = CTFont <name: Helvetica, size: 12.000000, matrix: 0x0> 
CTFontDescriptor <attributes: <CFBasicHash 0xd345ed0 [0x1227b38]>{type = mutable dict, count = 1, 
entries => 
    1 : <CFString 0xabbd0 [0x1227b38]>{contents = "NSFontNameAttribute"} = <CFString 0x6d69720 [0x1227b38]>{contents = "Helvetica"} 
} 
> 
} 
} 

我注意到,描述不包括字符串,但包括字符数组。所以该行可能不会保留字符串的副本;它解析字符串以创建它自己的私人表示。

下面是改变后的字符串行的描述:

2012-08-03 12:11:10.722 coretext[44780:f803] line = CTLine: run count = 1, string range = (0, 5), width = 28.6758, A/D/L = 9.24023/2.75977/0, glyph count = 5 
{ 
    CTRun: string range = (0, 5), characters = { 0x0077, 0x006f, 0x0072, 0x006c, 0x0064 }, attributes = 
<CFBasicHash 0x6d69ce0 [0x1227b38]>{type = mutable dict, count = 1, 
entries => 
    2 : <CFString 0xab1b0 [0x1227b38]>{contents = "NSFont"} = CTFont <name: Helvetica, size: 12.000000, matrix: 0x0> 
CTFontDescriptor <attributes: <CFBasicHash 0xd345ed0 [0x1227b38]>{type = mutable dict, count = 1, 
entries => 
    1 : <CFString 0xabbd0 [0x1227b38]>{contents = "NSFontNameAttribute"} = <CFString 0x6d69720 [0x1227b38]>{contents = "Helvetica"} 
} 
> 
} 
} 

我们可以看到,该行并没有改变其字形计数或它的字符数组。从这里我们可以得出结论,当你改变字符串时,该行不会改变。您可以通过在更改字符串之前和之后实际绘制线来进一步测试。我把它作为读者的练习。

+0

真的吗?如果retainCount **发生了**变化,那么我们无法确定为什么,但在这种情况下它并没有改变,并且由于您是唯一所有者,您知道没有其他人保留它。在这个非常特殊的情况下,它确实告诉我们一些事情。太糟糕了,我们不能投票评论... – lnafziger 2012-08-03 19:19:32

+0

@Inafziger,只是一个供参考,你回应的原始评论已经消失了。现在看起来像是对答案的评论。我起初很困惑...... – 2012-08-03 19:40:28

+0

我删除了评论,因为在两个小时之后,我能够弄清楚这个答案是说“你可以释放这个字符串”,只是以一种可怕的,可怕的方式。 – hooleyhoop 2012-08-03 19:46:47

0

MutableString的东西不应该是一个问题 - CTLine文档清楚地表明这是不可变的状态。所以在创建之后无法对其进行更改 - 这就是您所需要知道的。不管它是复制,保留还是其他什么,或者你对创建CTLine的字符串做了什么都没有关系 - 它是一个冻结对象。

此外,仅仅为了支持马特的优秀答案 - 保留/释放的重点是摆脱对象必须“拥有”的可怕想法。以这种方式思考是没有用的。例如,我们从来没有责任去释放物体,物体的寿命是不可知的。保留/释放更像是一个简单的垃圾收集器。

你只需要遵循简单的规则,这些规则最好从苹果公司的来源直接学习,他们有很好的文档记录。总是遵循这些简单的规则。

所以,不,你不会在每个函数的文档中看到特定的内存管理指南。它确实不是必需的。如果还没有点击,你需要回到基础。

相关问题