{"id":924,"date":"2012-07-05T09:42:52","date_gmt":"2012-07-04T21:42:52","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=924"},"modified":"2012-07-05T09:43:13","modified_gmt":"2012-07-04T21:43:13","slug":"cfstringref-and-tcfstrings","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/924\/","title":{"rendered":"CFStringRef and TCFString(s)"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>In the comments on yesterdays initial post in a series following the experiences of porting an <em>Objective-C<\/em> sample to XE2, a number of people have asked why I didn&#8217;t use the <strong>TCFString<\/strong> record type in <strong>System.Mac.CFUtils<\/strong> to get the CFStringRef references that I required.  The reason is embarrassingly simple.<!--more--><\/p>\n<p>I didn&#8217;t know about it at the time.  \ud83d\ude42<\/p>\n<p>But now that I do, I am now curious as to how anyone <em>does<\/em> stumble across it.  Even more curious as to the experiences of people have found if\/when they use it.<\/p>\n<p>First of all, there is no mention of it&#8217;s contents or relevance in the XE2 documentation.  There is not even a passing reference to it in the help page specifically about &#8220;<a href=\"http:\/\/docwiki.embarcadero.com\/RADStudio\/en\/Mac_OS_X_Application_Development\">Mac OS X Application Development<\/a>&#8221; or any of the linked articles discussing &#8220;<em>Considerations for Cross-Platform Applications<\/em>&#8220;.<\/p>\n<p>In fact, the only mention of it is in the <a href=\"http:\/\/docwiki.embarcadero.com\/RADStudio\/en\/Unit_Names_Alphabetical_List_with_Unit_Scopes\">list of unit names and scopes<\/a>.<\/p>\n<p>However, being now aware of it I took a look and quickly concluded that this unit was not a serious attempt to expose these <em>CoreFoundation<\/em> types to XE2 developers &#8211; more likely it looks like a unit that was created to prop up the <em>FireMonkey<\/em> developers (i.e. the creators, not consumers, of the <em>FireMonkey<\/em> framework) but not intended for general purpose use.<\/p>\n<p>Not only are the encapsulations incomplete they are also dangerously naive &#8211;  there is a complete lack of error checking.  They are essentially the XE2 equivalent of <strong>StrPCopy()<\/strong> (and when was the last time you used that?)<\/p>\n<p>Even if that were not the case, this sort of thing has a really, really bad smell about it to me:<\/p>\n<pre class=\"brush: delphi; title: ; notranslate\" title=\"\">\r\n  var\r\n    s: String;\r\n    str: CFStringRef;\r\n  begin\r\n     :\r\n    s   := 'The quick brown fox...';\r\n    str := TCFString.Create(s).Value;\r\n     :\r\n  end;\r\n<\/pre>\n<p>Didn&#8217;t we just leak a <strong>TCFString<\/strong> ?<\/p>\n<p>No, we didn&#8217;t, because <strong>TCFString<\/strong> is a record type, not a class.  It&#8217;s just that to use this &#8220;type&#8221; we are forced to write code that smells really, really bad and is visually indistinguishable from flat out wrong code.<\/p>\n<p>However, inside that <strong>TCFString<\/strong> record is a <strong>CFStringRef<\/strong> value, and on the <em>CoreFoundation<\/em> side of things we do (I think) need to call <strong>CFRelease()<\/strong> on that reference at some point.  Curiously as far as I can tell this won&#8217;t happen when the <strong>TCFString<\/strong> record is disposed and one of the omissions in the implementation of this &#8220;encapsulation&#8221; is the absence of any explicit &#8220;Release&#8221; method which you might expect to exist.  You can indicate that you want the ref to be Release&#8217;d as part of conversion to a String or a Char, but that&#8217;s it.<\/p>\n<h3>Would You Expect Your Dog to Eat This ?<\/h3>\n<p>Perhaps if we look at the way this type is used within the Delphi <em>RTL<\/em> code itself, we will get a better idea of how it should be used.  Without documentation &#8220;Use the Source&#8221; has always been a great way to learn such things, thanks to the availability of the <em>RTL\/VCL<\/em> source code.<\/p>\n<p><em>(Apologies to users of the Starter Editions&#8230; you are expected to get &#8220;Started&#8221; without even this assistance)<\/em><\/p>\n<p>So let&#8217;s find a few usages of <strong>TCFString<\/strong> in the <em>RTL\/FMX<\/em> code to look at &#8230;<\/p>\n<p>Oh.<\/p>\n<p>There&#8217;s actually only <em>one<\/em> area where this is used at all: <strong>System.DateUtils<\/strong><\/p>\n<p>And it isn&#8217;t used to convert from a Delphi <strong>String<\/strong> to a <strong>CFStringRef<\/strong> but rather the exact opposite &#8211; to capture a <strong>CFStringRef<\/strong> temporarily for the purposes of converting to a Delphi <strong>String<\/strong>.<\/p>\n<p>Well, maybe <em>FireMonkey<\/em> doesn&#8217;t need to do this string-type shuffle at all ?  Maybe this <strong>TCFString<\/strong> type is provided as a convenience for the rest of us but wasn&#8217;t actually needed in <em>FMX<\/em> after all.<\/p>\n<p>Well, no.<\/p>\n<p>If we search for calls to <strong>CFRelease()<\/strong> (notably missing from <strong>TCFString<\/strong> remember) in the <em>FMX<\/em> source, then we find numerous calls involving strings, and those strings are <strong>CFStringRef<\/strong> values that are initialised using the <em>CoreFoundation<\/em> <strong>CFStringCreate&#8230;<\/strong> factory functions.<\/p>\n<h3>The Real Question &#8230;<\/h3>\n<p>The question perhaps shouldn&#8217;t be why don&#8217;t *I* use <strong>TCFString<\/strong> for such things, but rather <em>why don&#8217;t Embarcadero use it themselves<\/em> ?<\/p>\n<p>I at least have the excuse that Embarcadero didn&#8217;t tell me about it or show me how to use it.  They have no such excuse.<\/p>\n<h3>Could You Pass the Smelling Salts Please &#8230; ?<\/h3>\n<p>But if the smell so far is bad, it&#8217;s about to get even worse, because in searching for &#8220;TCFString&#8221; we find that there are not one but <strong><em>TWO<\/em><\/strong> <strong>TCFString<\/strong> record types with this name.<\/p>\n<p>There is the one in <strong>System.Mac.CFUtils<\/strong> but there is also one in <strong>System.SysUtils<\/strong>.  This one is a private implementation detail to this unit and provides only a subset of the &#8220;real&#8221; <strong>TCFString<\/strong>.<\/p>\n<p>This is perhaps a clumsy attempt to avoid a circular unit reference or some awkward name-spacing issue with the units as the <strong>SysUtils<\/strong> unit would otherwise have to use the <strong>Mac.CFUtils<\/strong> unit which itself already uses the <strong>SysUtils<\/strong> unit ?<\/p>\n<p>I suspect that the developers working on <strong>SysUtils<\/strong> fell foul of the admonishment in the source to avoid adding any units to the implementation uses clause and so fell back on good old &#8220;Copy\/Paste&#8221; code re-use.<\/p>\n<p>Ah, progress in robust software development practices.  Who needs it ?<\/p>\n<p>Ironically, if instead of creating a new, undocumented unit the <strong>TCFString<\/strong> type and it&#8217;s brethren had been put in the unit that would make most sense (to me), i.e. <strong>MacAPI.CoreFoundation<\/strong>, there would have been no need for such bad odours as <strong>SysUtils<\/strong> already uses this unit.<\/p>\n<h3>Are You Eating the Food that Embarcadero Can&#8217;t Bring Themselves to Eat?<\/h3>\n<p>So, I am curious &#8211; is <em>anyone<\/em> using <strong>TCFString<\/strong> for anything other than converting <strong>CFStringRef<\/strong> values to Delphi strings, and if so, how are you finding it ?<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">4<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> In the comments on yesterdays initial post in a series following the experiences of porting an Objective-C sample to XE2, a number of people have asked why I didn&#8217;t use the TCFString record type in System.Mac.CFUtils to get the CFStringRef references that I required. The reason is embarrassingly simple.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4,143],"tags":[161,162,159,94,292,138],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-eU","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":760,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/760\/","url_meta":{"origin":924,"position":0},"title":"Platform Independence Version Dependencies in the XE2 RTL","date":"14 Sep 2011","format":false,"excerpt":"So I have spent about a week now with XE2 and FireMonkey and thought I would share some of the experience so far. After an initial peek and poke around, the first order of business for me was to migrate some of my existing code to the new RTL. First\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":791,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/791\/","url_meta":{"origin":924,"position":1},"title":"Why Does My OSX FireMonkey App Think It Is a Console App ?","date":"15 Sep 2011","format":false,"excerpt":"Because System.IsConsole is hardwired to TRUE on MAC OS: This is actually also the case for $ifdef LINUX, but nobody is likely to notice that, at least not just yet. :) But it caused me no end of confusion when my FireMonkey app behaved one way on Windows and a\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":843,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/843\/","url_meta":{"origin":924,"position":2},"title":"XE2 Update #4 On The Horizon","date":"19 Jan 2012","format":false,"excerpt":"The release notes for Update #4 have appeared online, signalling the imminent arrival no doubt of the update itself. The good news if you are using FireMonkey is that this is a significant update, including functionality for printing. The bad news is that like update #1, this update is not\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1974,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1974\/","url_meta":{"origin":924,"position":3},"title":"Improved Quality in Delphi &#8211; Yeah Right","date":"28 Oct 2013","format":false,"excerpt":"Here in Aotearoa there is a beer company called \"Tui\", named in turn for a native bird. As well as a series of TV ads voiced by the great Tom Baker, Tui are famous here for their \"Yeah, right!\" billboard ads. I felt compelled to make one for Delphi. I\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/tui.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":900,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/900\/","url_meta":{"origin":924,"position":4},"title":"Porting the Objective-C CFFTPSample to XE2: Part 1","date":"04 Jul 2012","format":false,"excerpt":"On the NZ DUG email list (yes, we still have those here) a question was recently posted asking for help with getting some FTP code working on OSX, using XE2. This coincided nicely with my reaching a point in my Objective-C learning where this sort of exercise was of interest\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":815,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/815\/","url_meta":{"origin":924,"position":5},"title":"Something the XE2 Un\/Installer Should Tell You&#8230;","date":"30 Sep 2011","format":false,"excerpt":"If you are about to install update #1 for Delphi XE2, the first thing you will need to do is uninstall your current version. But beware - the uninstaller doesn't tell you something quite important. When uninstalling a folder in the XE2 Program Files area (\"InstallAware\") cannot be deleted, presumably\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/924"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=924"}],"version-history":[{"count":10,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/924\/revisions"}],"predecessor-version":[{"id":934,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/924\/revisions\/934"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=924"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=924"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=924"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}