2012-08-03 71 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的字符串做了什麼都沒有關係 - 它是一個凍結對象。

此外,僅僅爲了支持馬特的優秀答案 - 保留/釋放的重點是擺脫對象必須「擁有」的可怕想法。以這種方式思考是沒有用的。例如,我們從來沒有責任去釋放物體,物體的壽命是不可知的。保留/釋放更像是一個簡單的垃圾收集器。

你只需要遵循簡單的規則,這些規則最好從蘋果公司的來源直接學習,他們有很好的文檔記錄。總是遵循這些簡單的規則。

所以,不,你不會在每個函數的文檔中看到特定的內存管理指南。它確實不是必需的。如果還沒有點擊,你需要回到基礎。

相關問題