<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Vincent Gable's Blog &#187; NSDictionary</title>
	<atom:link href="http://vgable.com/blog/tag/nsdictionary/feed/" rel="self" type="application/rss+xml" />
	<link>http://vgable.com/blog</link>
	<description>my weblog.</description>
	<lastBuildDate>Tue, 29 Nov 2011 22:20:23 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>NSDictionary Copies It&#8217;s Keys</title>
		<link>http://vgable.com/blog/2010/07/08/nsdictionary-copies-its-keys/</link>
		<comments>http://vgable.com/blog/2010/07/08/nsdictionary-copies-its-keys/#comments</comments>
		<pubDate>Thu, 08 Jul 2010 17:55:29 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Bug Bite]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[copy]]></category>
		<category><![CDATA[Documentation]]></category>
		<category><![CDATA[NSDictionary]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/?p=643</guid>
		<description><![CDATA[An NSDictionary will retain it&#8217;s objects, and copy it&#8217;s keys. Here are some effects this has had on code I&#8217;ve worked on. Sometimes you get the same object you put in, sometimes not. Immutable objects are optimized to return themselves as a copy. (But with some exceptions!). So the following code: NSDictionary *d = [NSDictionary [...]]]></description>
			<content:encoded><![CDATA[<p>An <code>NSDictionary</code> will <code>retain</code> it&#8217;s objects, and <code>copy</code> it&#8217;s keys. </p>
<p>Here are some effects this has had on code I&#8217;ve worked on.</p>
<ul>
<li>
<strong>Sometimes you get the same object you put in, sometimes not</strong>.<br />
<a href="http://vgable.com/blog/2008/11/14/prefer-copy-over-retain/">Immutable objects are optimized to return themselves as a <code>copy</code></a>. (But with some exceptions!). So the following code:</p>
<pre>
	NSDictionary *d = [NSDictionary dictionaryWithObject:@"object" forKey:originalKey];
	for(id aKey in d)
		if(aKey == originalKey)
			NSLog(@"Found the original key!");
</pre>
<p>Might print &#8220;Found the original key!&#8221;, and might not, depending on how <code>[originalKey  copy]</code> is implemented. For this reason, <strong>never use pointer-equality when comparing keys</strong>.</p>
<li><strong>Mutable objects make bad keys</strong>. If <code>x</code> is a mutable <code>NSObject</code>, <code>[x copy] is an </code><em>immutable</em> copy of <code>x</code>, <em>at that point in time</em>. Any changes to <code>x</code> are <em>not</em> reflected in the copy. For example,
<pre>
	[dict setObject:x forKey:key];
	//...code that changes key, but not dict
	<a href="http://vgable.com/blog/2008/12/04/nsassert-considered-harmful/">assert</a>([[dict objectForKey:key] isEqual:x]); //fails!
</pre>
<p>Because the <code>copy</code> is an immutable object, it will blow up if you try to mutate it.</p>
<pre>
	NSMutableString *key = //something...
	[dict setObject:x forKey:key];
	for(NSMutableString *aKey in dict)
		[aKey appendString:@"2"]; //Error, aKey isn't mutable, even though key is!
</pre>
</li>
<li>
<strong>View objects make bad keys</strong>. Views have state related to  the screen: their <code>frame</code>, position in the view hierarchy, animation layers, etc. When you <code>copy</code> a view object, the copy won&#8217;t (always) be <code>isEqual:</code> to the original, because it&#8217;s not on the screen in exactly the same way.
</li>
</li>
<li>
<strong>Your classes must support <code>NSCopying</code> to be used as a key in an <code>NSDictionary</code></strong>, you can&#8217;t just <a href="http://mikeash.com/pyblog/friday-qa-2010-06-18-implementing-equality-and-hashing.html">implement <code>-hash</code> and <code>-isEqual:</code></a> in your custom classes.
</li>
</ul>
<p>Of course, this isn&#8217;t a complete list of every way key-copying can trip you up. But if you understand what <code>copy</code> means in Cocoa, and remember how <code>NSDictionary</code> works, you&#8217;ll be able to avoid or quickly solve any issues.</p>
<h3>How to Document Such Behavior Better Than Apple Did</h3>
<p>Given what we know about <code>NSDictionary</code>, what&#8217;s wrong with the following snippit from <code>NSDictionary.h</code>?</p>
<pre>
@interface NSMutableDictionary : NSDictionary
- (void)setObject:(id)anObject forKey:(id)aKey;
@end
</pre>
<p>Answer: <code> aKey </code> needs to implement <code>NSCopying</code>, so it should be of type <code>(id&lt;NSCopying&gt;)</code> instead of type <code>(id)</code>. That way, the header is self-documenting, and, if like most smart programmers, you&#8217;re using autocomplete to type out Cocoa&#8217;s long method names, the auto-completed template will be self-documenting too.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2010/07/08/nsdictionary-copies-its-keys/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Concise NSDictionary and NSArray Lookup</title>
		<link>http://vgable.com/blog/2009/05/15/concise-nsdictionary-and-nsarray-lookup/</link>
		<comments>http://vgable.com/blog/2009/05/15/concise-nsdictionary-and-nsarray-lookup/#comments</comments>
		<pubDate>Fri, 15 May 2009 19:13:02 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Research]]></category>
		<category><![CDATA[Sample Code]]></category>
		<category><![CDATA[Usability]]></category>
		<category><![CDATA[NSArray]]></category>
		<category><![CDATA[NSDictionary]]></category>
		<category><![CDATA[Programming Language Design]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2009/05/15/concise-nsdictionary-and-nsarray-lookup/</guid>
		<description><![CDATA[I started writing a list of ways I thought Objective-C could be improved, and I realized that many of my wishes involved more compact syntax. For example [array objectAtIndex:1] is so verbose I think it diminishes readability, compared to array[1]. I can&#8217;t quite match that brevity (can you, by using Objective-C++?), but with a one-line [...]]]></description>
			<content:encoded><![CDATA[<p>I started writing a list of ways I thought Objective-C could be improved, and I realized that many of my wishes involved more compact syntax. For example <code>[array objectAtIndex:1]</code> is so verbose I think it diminishes readability, compared to <code>array[1]</code>.</p>
<p>I can&#8217;t quite match that brevity (can you, by using Objective-C++?), but with a one-line category, you can say, <code>x = [array:1];</code>.</p>
<pre>
@interface NSArray (ConciseLookup)
- (id):(NSUInteger)index;
@end
@implementation NSArray (ConciseLookup)
- (id):(NSUInteger)index;
{
	return [self objectAtIndex:index];
}
@end
</pre>
<p>My question is: <strong>do you find this compact &#8220;syntax&#8221; useful at all, or is it added complexity with no substantial code compression?</strong> Personally I think the latter, but the number of wishes I had involving  more concise Objective-C syntax makes me wonder&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2009/05/15/concise-nsdictionary-and-nsarray-lookup/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>-[NSURL isEqual:] Gotcha</title>
		<link>http://vgable.com/blog/2009/04/22/nsurl-isequal-gotcha/</link>
		<comments>http://vgable.com/blog/2009/04/22/nsurl-isequal-gotcha/#comments</comments>
		<pubDate>Thu, 23 Apr 2009 00:05:07 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Bug Bite]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[MacOSX]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Sample Code]]></category>
		<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[isEqual:]]></category>
		<category><![CDATA[NSArray]]></category>
		<category><![CDATA[NSDictionary]]></category>
		<category><![CDATA[NSSet]]></category>
		<category><![CDATA[NSString]]></category>
		<category><![CDATA[NSURL]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2009/04/22/nsurl-isequal-gotcha/</guid>
		<description><![CDATA[BREAKING UPDATE: Actually comparing the -absoluteURL or -absoluteString of two NSURLs that represent a file is not good enough. One may start file:///, and the other file://localhost/, and they will not be isEqual:! A work around is to compare the path of each NSURL. I&#8217;m still looking into the issue, but for now I am [...]]]></description>
			<content:encoded><![CDATA[<p>BREAKING UPDATE: Actually comparing the <code>-absoluteURL</code> or <code>-absoluteString</code> of two <code>NSURL</code>s that represent a file is <em>not good enough</em>.  One may start <code>file:///</code>, and the other <code>file://localhost/</code>, and <em>they will not be <code>isEqual:</code></em>!  A work around is to compare the <code>path</code> of each <code>NSURL</code>. I&#8217;m still looking into the issue, but for now I am using the following method to compare <code>NSURL</code>s.</p>
<pre>@implementation NSURL (IsEqualTesting)
- (BOOL) isEqualToURL:(NSURL*)otherURL;
{
	return [[self absoluteURL] isEqual:[otherURL absoluteURL]] ||
	[self isFileURL] &#038;&#038; [otherURL isFileURL] &#038;&#038;
	([[self path] isEqual:[otherURL path]]);
}
@end
</pre>
<p><code>[a isEqual:b]</code> may report <code>NO</code> for two <code>NSURL</code>s that both resolve to the same resource (website, file, whatever). So <strong>compare <code>NSURL</code>s like <code>[[a absoluteString] isEqual:[b absoluteString]]</code></strong>. It&#8217;s important to be aware of this gotcha, because URLs are Apple&#8217;s preferred way to represent file paths, and APIs are starting to require them. <strong>Equality tests that worked for <code>NSString</code> file-paths may fail with <code>NSURL</code> file-paths.</strong></p>
<p><a href="http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/occ/instm/NSURL/isEqual:">The official documentation says</a></p>
<blockquote><p> two <code>NSURLs</code> are considered equal if they both have the same base <a href="http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/occ/instm/NSURL/baseURL"><code>baseURL</code></a> and <a href="http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/occ/instm/NSURL/relativeString"><code>relativeString</code></a>.</p></blockquote>
<p>Furthermore,</p>
<blockquote><p>An <code>NSURL</code> object is composed of two parts—a potentially nil base URL and a string that is resolved relative to the base URL. An <code>NSURL</code> object whose string is fully resolved without a base is considered absolute; all others are considered relative.
</p></blockquote>
<p>In other words, two <code>NSURL</code> objects can resolve to the same absolute URL, but have a different base URL, and be considered <code>!isEqual:</code>.</p>
<p>An example should make this all clear,</p>
<pre>
NSURL *VGableDotCom = [NSURL URLWithString:@"http://vgable.com"];
NSURL *a = [[NSURL alloc] initWithString:@"blog" relativeToURL:VGableDotCom];
NSURL *b = [[NSURL alloc] initWithString:@"http://vgable.com/blog" relativeToURL:nil];
<a href="http://vgable.com/blog/2008/08/05/simpler-logging-2/">LOG_INT</a>([a isEqual:b]);
<a href="http://vgable.com/blog/2008/08/05/simpler-logging-2/">LOG_INT</a>([[a absoluteURL] isEqual:[b absoluteURL]]);
<a href="http://vgable.com/blog/2008/08/05/simpler-logging-2/">LOG_ID</a>([a absoluteURL]);
<a href="http://vgable.com/blog/2008/08/05/simpler-logging-2/">LOG_ID</a>([b absoluteURL]);
</pre>
<blockquote><p>
[a isEqual:b] = 0<br />
[[a absoluteURL] isEqual:[b absoluteURL]] = 1<br />
[a absoluteURL] = http://vgable.com/blog<br />
[b absoluteURL] = http://vgable.com/blog
</p></blockquote>
<p>Remember that <strong>collections use <code>isEqual:</code> to determine equality, so you may have to convert an <code>NSURL</code> to an <code> absoluteURL</code> to get the behavior you expect, especially with <code>NSSet</code> and <code>NSDictionary</code>.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2009/04/22/nsurl-isequal-gotcha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>isEmpty?</title>
		<link>http://vgable.com/blog/2008/12/16/isempty/</link>
		<comments>http://vgable.com/blog/2008/12/16/isempty/#comments</comments>
		<pubDate>Wed, 17 Dec 2008 00:29:59 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Bug Bite]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Sample Code]]></category>
		<category><![CDATA[Usability]]></category>
		<category><![CDATA[Containers]]></category>
		<category><![CDATA[isEqual:]]></category>
		<category><![CDATA[nil]]></category>
		<category><![CDATA[NSArray]]></category>
		<category><![CDATA[NSData]]></category>
		<category><![CDATA[NSDictionary]]></category>
		<category><![CDATA[NSSet]]></category>
		<category><![CDATA[NSString]]></category>
		<category><![CDATA[NULL]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/12/16/isempty/</guid>
		<description><![CDATA[Checking if a Cocoa object is empty is a little harder then in other languages, say C++, (but easier in some ways). Because every object in Objective-C is actually a pointer to an object, there are two ways, obj, can be empty. obj = {} obj points to an object that is empty. Say an [...]]]></description>
			<content:encoded><![CDATA[<p>Checking if a Cocoa object is empty is a little harder then in other languages, say C++, (but easier in some ways). Because every object in Objective-C is actually a <em>pointer</em> to an object, there are two ways, <code>obj</code>, can be empty.  </p>
<p><strong><code>obj = {}</code></strong>
<p>
<code>obj</code> points to an object that is empty.  Say an array with 0 items, or the string <code>""</code>, etc..</p>
<p><strong><code>obj = nil</code></strong>
<p>
<code>obj</code>, the pointer <code>obj</code>, is <code>NULL</code>, <code>nil</code>, <code>0</code>, or whatever you want to call it.  You might argue that <code>obj</code> isn&#8217;t really an object, but it <em>is</em> empty, because there&#8217;s nothing in it.</p>
<h3>Bug:</h3>
<p>
When I first started writing Objective-C, I made the mistake of writing code like: <code>if([name isEqualToString:@""]){ ... }</code>, to test for empty strings.  And this code would work for a while until I used it in a situation where <code>name</code> was <code>nil</code>, and then, <a href="http://vgable.com/blog/2008/05/31/messages-to-nowhere/">because sending any method called on <code>nil</code> &#8220;returns&#8221; <code>NO</code></a>, I would have mysterious errors.  (<a href="http://vgable.com/blog/2008/12/11/there-are-worse-things-than-crashing/">Worse then a crash</a>, because it&#8217;s harder to track down.)</p>
<p><H3>Bug:</H3>
<p>
It&#8217;s tempting to avoid the previous bug, by explicitly testing for <code>nil</code> <em>and</em> <code>{}</code>.  Say with code like:</p>
<pre>if (email == nil || ![email isEqualTo:@""] )
&nbsp;&nbsp;&nbsp;email = @"An email address is required";</pre>
<p>But generally this is a bad idea.  It means more code, which means more places for a bug.  I know it&#8217;s only one trivial test, but I&#8217;m serious, when I say it&#8217;s asking for a bug &#8212; like the bug in the example above, which sets <code> email </code> to <code>@"An email address is required"</code>, whenever it is <em>not</em> the empty string, rather then when it <em>is</em> empty.  (Values have been changed tho protect the innocent but it&#8217;s a bug I&#8217;ve seen.)</p>
<p><H3>Solutions:</H3>
<p><a href="http://www.wilshipley.com/blog/2005/10/pimp-my-code-interlude-free-code.html">Wil Shipley suggests using the global function:</a><br />
<code><br />
static inline BOOL IsEmpty(id thing) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;return thing == nil<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|| ([thing respondsToSelector:@selector(length)]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#038;&#038; [(NSData *)thing length] == 0)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|| ([thing respondsToSelector:@selector(count)]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#038;&#038; [(NSArray *)thing count] == 0);<br />
}<br />
</code></p>
<p>I&#8217;ve been using his <code>IsEmpty()</code> for about a year. I&#8217;ve had zero problems with it, while it&#8217;s made my code more readable and concise.</p>
<p>Another solution is to take advantage of <a href="http://vgable.com/blog/2008/05/31/messages-to-nowhere/">what happens when you send a message to <code>nil</code></a>.  (To over-simplify, you get back 0 or <code>NO</code>.)  So you can just say &#8220;if <code>([obj count] == 0)</code> then <code>obj</code> is empty.&#8221;  This often means reversing your thinking, and testing &#8220;IsNotEmpty()&#8221; instead of &#8220;IsEmpty()&#8221;.  I don&#8217;t think it&#8217;s as clear is <code>IsEmpty()</code> in general, but in cases where it is, there you have it.</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/12/16/isempty/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Null-Terminated Argument Lists</title>
		<link>http://vgable.com/blog/2008/07/17/null-terminated-argument-lists/</link>
		<comments>http://vgable.com/blog/2008/07/17/null-terminated-argument-lists/#comments</comments>
		<pubDate>Fri, 18 Jul 2008 03:07:50 +0000</pubDate>
		<dc:creator>Vincent Gable</dc:creator>
				<category><![CDATA[Bug Bite]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Usability]]></category>
		<category><![CDATA[Containers]]></category>
		<category><![CDATA[nil]]></category>
		<category><![CDATA[NSArray]]></category>
		<category><![CDATA[NSDictionary]]></category>
		<category><![CDATA[NSSet]]></category>
		<category><![CDATA[NULL]]></category>

		<guid isPermaLink="false">http://vgable.com/blog/2008/07/17/null-terminated-argument-lists/</guid>
		<description><![CDATA[I was using +[NSDictionary dictionaryWithObjectsAndKeys:] to make a new dictionary, but one of the objects in the dictionary was the result of a call to a method that was returning nil, so the dictionary was incomplete. This got me thinking about NULL/nil terminated argument lists. I don&#8217;t think they are a great idea (the compiler [...]]]></description>
			<content:encoded><![CDATA[<p>I was using <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html#//apple_ref/occ/clm/NSDictionary/dictionaryWithObjectsAndKeys:">+[NSDictionary dictionaryWithObjectsAndKeys:]</a> to make a new dictionary, but one of the objects in the dictionary was the result of a call to a method that was returning <code>nil</code>, so the dictionary was incomplete.</p>
<p>This got me thinking about <code>NULL</code>/<code>nil</code> terminated argument lists.  I don&#8217;t think they are a great idea (the compiler should be able to handle the list-termination for you!), but I think they are an <em>especially bad idea</em> in Objective-C.</p>
<p>The problem that <strong>it&#8217;s very common to have a <code>nil</code> object in Objective-C</strong>, relative to, say C++.  Many Cocoa methods return <code>nil</code> on error.  <a href="http://vincentgable.com/blog/2008/05/31/messages-to-nowhere/">Since doing stuff with <code>nil</code> (generally) won&#8217;t cause an exception</a>, these <code>nil</code>s stick around much longer then in other languages.  As you can see, <code>nil</code> is a pretty poor choice of a sentinel value.</p>
<p>It&#8217;s the 21st century! The compiler <em>could</em> tell an Obj-C method using a variable-argument-list how many arguments are in the list.  This is trivial when all arguments are of type <code>id</code>.  Since Obj-C methods use a radically different syntax from C functions, it shouldn&#8217;t effect existing C-code.  Unfortunately, I don&#8217;t see this being added, because Objective-C is already so mature.</p>
<p>In the meantime.  <strong>Be a little more suspicious of any objective-C methods taking a <code>NULL</code>-terminated list</strong>.  I wish I had a perfect solution to avoid them, but I don&#8217;t!  Sometimes they are the best way to do something.  If you have a great work-around for constructing, say an <code>NSDictionary</code> with a variable number of key/values please let me know!</p>
]]></content:encoded>
			<wfw:commentRss>http://vgable.com/blog/2008/07/17/null-terminated-argument-lists/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

