<?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>iPhoneGeek 爱疯极客</title>
	<atom:link href="http://www.iphone-geek.cn/feed" rel="self" type="application/rss+xml" />
	<link>http://www.iphone-geek.cn</link>
	<description>iPhone 新闻，编程，技巧与提示，代码，教程</description>
	<lastBuildDate>Wed, 01 Sep 2010 06:51:34 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Xcode不支持iPhoe OS 3.2.1的解决方法</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/xcode%e4%b8%8d%e6%94%af%e6%8c%81iphoe-os-3-2-1%e7%9a%84%e8%a7%a3%e5%86%b3%e6%96%b9%e6%b3%95</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/xcode%e4%b8%8d%e6%94%af%e6%8c%81iphoe-os-3-2-1%e7%9a%84%e8%a7%a3%e5%86%b3%e6%96%b9%e6%b3%95#comments</comments>
		<pubDate>Wed, 01 Sep 2010 06:15:10 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[基础]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[系统安装]]></category>
		<category><![CDATA[调试]]></category>
		<category><![CDATA[Xcode]]></category>
		<category><![CDATA[提示与技巧]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1069</guid>
		<description><![CDATA[最近iPad升级到iPhone 3.2.1，今天准备进行真机调试，猛然发现Xcode下出现下列错误：

The version of iPhone OS on &#8220;xxxx&#8221; does not match any of the versions of iPhone OS supported for development with this copy of Xcode. Please restore the device to a version of the OS listed below. If necessary, the latest version of Xcode is available here.

Google 了一下，发现是3.2.1的目录在DeviceSupport下不存在。解决办法是用最接近的OS版本使用ln命令进行链接。不过在操作过程中有两个问题：

1. 不知什么原因，ln -s 命令后总是为文件而不是目录
2. 不知OS 3.2的build number

于是，采用最笨但最为有效的方法：

在/Developer/Platforms/iPhoneOS.platform/DeviceSupport目录下创建3.2.1目录，然后，将3.2下所有文件及目录复制到3.2.1下，重新启动Xcode，问题解决。
]]></description>
			<content:encoded><![CDATA[<p>最近iPad升级到iPhone 3.2.1，今天准备进行真机调试，猛然发现Xcode下出现下列错误：<br />
<br class="spacer_" /><br />
The version of iPhone OS on &#8220;xxxx&#8221; does not match any of the versions of iPhone OS supported for development with this copy of Xcode. Please restore the device to a version of the OS listed below. If necessary, the latest version of Xcode is available here.<br />
<br class="spacer_" /><br />
Google 了一下，发现是3.2.1的目录在DeviceSupport下不存在。解决办法是用最接近的OS版本使用ln命令进行链接。不过在操作过程中有两个问题：<br />
<br class="spacer_" /><br />
1. 不知什么原因，ln -s 命令后总是为文件而不是目录<br />
2. 不知OS 3.2的build number<br />
<br class="spacer_" /><br />
于是，采用最笨但最为有效的方法：<br />
<br class="spacer_" /><br />
在/Developer/Platforms/iPhoneOS.platform/DeviceSupport目录下创建3.2.1目录，然后，将3.2下所有文件及目录复制到3.2.1下，重新启动Xcode，问题解决。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/xcode%e4%b8%8d%e6%94%af%e6%8c%81iphoe-os-3-2-1%e7%9a%84%e8%a7%a3%e5%86%b3%e6%96%b9%e6%b3%95/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Open source CoverFlow</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/open-source-coverflow</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/open-source-coverflow#comments</comments>
		<pubDate>Sat, 21 Aug 2010 09:55:00 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[图形图像]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[链接]]></category>
		<category><![CDATA[开源项目]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1063</guid>
		<description><![CDATA[使用OpenGL ES的开源Cover Flow，据说有好几个上架程序中都有使用，见http://www.chaosinmotion.com/flowcover.m。
]]></description>
			<content:encoded><![CDATA[<p>使用OpenGL ES的开源Cover Flow，据说有好几个上架程序中都有使用，见<a href="http://www.chaosinmotion.com/flowcover.m">http://www.chaosinmotion.com/flowcover.m</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/open-source-coverflow/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>修改公司名称的“新”方法</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bf%ae%e6%94%b9%e5%85%ac%e5%8f%b8%e5%90%8d%e7%a7%b0%e7%9a%84%e2%80%9c%e6%96%b0%e2%80%9d%e6%96%b9%e6%b3%95</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bf%ae%e6%94%b9%e5%85%ac%e5%8f%b8%e5%90%8d%e7%a7%b0%e7%9a%84%e2%80%9c%e6%96%b0%e2%80%9d%e6%96%b9%e6%b3%95#comments</comments>
		<pubDate>Fri, 20 Aug 2010 04:52:41 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[基础]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1064</guid>
		<description><![CDATA[以前发过一篇文章介绍怎样修改Xcode中的公司名称，见怎样替换Xcode中__MyCompanyName__。
现在（不知是从Xcode哪个版本开始，我是3.2.3）可以有更简单的方法修改公司名称，而且还可以在基于项目修改。方法如下：
1. 右击项目名称，选择“Get Info&#8230;”
2. 在“General Settings”一栏中可以看到“Organization Name”，修改它，那么本项目中的公司名称就修改了。
]]></description>
			<content:encoded><![CDATA[<p>以前发过一篇文章介绍怎样修改Xcode中的公司名称，见<a href="技巧与提示/怎样替换xcode中__mycompanyname__">怎样替换Xcode中__MyCompanyName__</a>。</p>
<p>现在（不知是从Xcode哪个版本开始，我是3.2.3）可以有更简单的方法修改公司名称，而且还可以在基于项目修改。方法如下：</p>
<p>1. 右击项目名称，选择“Get Info&#8230;”<br />
2. 在“General Settings”一栏中可以看到“Organization Name”，修改它，那么本项目中的公司名称就修改了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bf%ae%e6%94%b9%e5%85%ac%e5%8f%b8%e5%90%8d%e7%a7%b0%e7%9a%84%e2%80%9c%e6%96%b0%e2%80%9d%e6%96%b9%e6%b3%95/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>怎样离线使用iPhone SDK文档</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e6%80%8e%e6%a0%b7%e7%a6%bb%e7%ba%bf%e4%bd%bf%e7%94%a8iphone-sdk%e6%96%87%e6%a1%a3</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e6%80%8e%e6%a0%b7%e7%a6%bb%e7%ba%bf%e4%bd%bf%e7%94%a8iphone-sdk%e6%96%87%e6%a1%a3#comments</comments>
		<pubDate>Wed, 18 Aug 2010 06:34:38 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[基础]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[Xcode]]></category>
		<category><![CDATA[提示与技巧]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1055</guid>
		<description><![CDATA[我是用Dell机安装的雪豹系统，由于没有无线网卡的支持，所以上网很不方便。在使用Xcode进行iPhone编程时，有时需要参考iPhone SDK的文档，不过每次Control+Click后，Xcode都会试图连接Internet，进行在线读取。有什么方法能够把资料下载到硬盘上进行离线阅读吗？

答案是肯定的。首先去Xcode的Preference中的Documentation Sets下，选择所需的docset，这里是iPhone 4.0 Reference Library，右击选择“Get Info&#8230;”，找到Feed URL：

http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_0.atom

用浏览器打开，下面列出了许多版本，在Windows下你就可以使用迅雷下载了。

下载后，拷贝到Mac的/Developer/Documentations/Docset目录下，使用终端命令：


sudo xar -xf 下载的文件名.xar


将其解压，然后使用:


sudo chown -R -P devdocs 解压后的文件名.docset


将文档的所有者改为devdocs。打开Xcode就可以离线浏览了。
]]></description>
			<content:encoded><![CDATA[<p>我是用Dell机安装的雪豹系统，由于没有无线网卡的支持，所以上网很不方便。在使用Xcode进行iPhone编程时，有时需要参考iPhone SDK的文档，不过每次Control+Click后，Xcode都会试图连接Internet，进行在线读取。有什么方法能够把资料下载到硬盘上进行离线阅读吗？<br />
<br class="spacer_" /><br />
答案是肯定的。首先去Xcode的Preference中的Documentation Sets下，选择所需的docset，这里是iPhone 4.0 Reference Library，右击选择“Get Info&#8230;”，找到Feed URL：<br />
<br class="spacer_" /><br />
<a "http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_0.atom">http://developer.apple.com/rss/com.apple.adc.documentation.AppleiPhone4_0.atom</a><br />
<br class="spacer_" /><br />
用浏览器打开，下面列出了许多版本，在Windows下你就可以使用迅雷下载了。<br />
<br class="spacer_" /><br />
下载后，拷贝到Mac的/Developer/Documentations/Docset目录下，使用终端命令：<br />
<br class="spacer_" /></p>
<blockquote><p>
sudo xar -xf 下载的文件名.xar
</p></blockquote>
<p><br class="spacer_" /><br />
将其解压，然后使用:<br />
<br class="spacer_" /></p>
<blockquote><p>
sudo chown -R -P devdocs 解压后的文件名.docset
</p></blockquote>
<p><br class="spacer_" /><br />
将文档的所有者改为devdocs。打开Xcode就可以离线浏览了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e6%80%8e%e6%a0%b7%e7%a6%bb%e7%ba%bf%e4%bd%bf%e7%94%a8iphone-sdk%e6%96%87%e6%a1%a3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Navigation-Based应用程序iPad模板</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/navigation-based%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8fipad%e6%a8%a1%e6%9d%bf</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/navigation-based%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8fipad%e6%a8%a1%e6%9d%bf#comments</comments>
		<pubDate>Sat, 14 Aug 2010 10:45:41 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[基础]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[用户界面]]></category>
		<category><![CDATA[Xcode]]></category>
		<category><![CDATA[提示与技巧]]></category>
		<category><![CDATA[模板]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1050</guid>
		<description><![CDATA[准备为iPad写一个Navigation-Based程序，却发现XCode 3.2中根本没有iPad的Navigation-Based程序的模板。Apple推荐在iPad下使用Split-View程序，但我并不想这样做，原因是我的iPad程序以后可能要放到iPhone中去，所以我需要一个Universal版。如果我在iPad下使用Split-View，那么这两个版本相差太大，所以我觉得都使用Navigation-Based程序。

试了半天想修改iPhone的Navigation-Based程序的模板到iPad下，却没有成功，在网上搜了一下，终于找到一个别人做好的。下面是下载地址。可以使用如下命令将其加到XCode的模板中：


mkdir -p &#8220;$HOME/Library/Application Support/Developer/Shared/XCode/Project Templates/My Templates&#8221;
cd &#8220;$HOME/Library/Application Support/Developer/Shared/XCode/Project Templates/My Templates&#8221;
git clone git://github.com/benellingson/Universal-Navigation-based-Application.git
rm -rf &#8220;Universal-Navigation-based-Application/.git&#8221;


或者下载zip文件，在创建了目录后，将zip解压其下。
]]></description>
			<content:encoded><![CDATA[<p>准备为iPad写一个Navigation-Based程序，却发现XCode 3.2中根本没有iPad的Navigation-Based程序的模板。Apple推荐在iPad下使用Split-View程序，但我并不想这样做，原因是我的iPad程序以后可能要放到iPhone中去，所以我需要一个Universal版。如果我在iPad下使用Split-View，那么这两个版本相差太大，所以我觉得都使用Navigation-Based程序。<br />
<br class="spacer_" /><br />
试了半天想修改iPhone的Navigation-Based程序的模板到iPad下，却没有成功，在网上搜了一下，终于找到一个别人做好的。下面是下载<a href="http://github.com/benellingson/Universal-Navigation-based-Application">地址</a>。可以使用如下命令将其加到XCode的模板中：<br />
<br class="spacer_" /></p>
<blockquote><p>
mkdir -p &#8220;$HOME/Library/Application Support/Developer/Shared/XCode/Project Templates/My Templates&#8221;</p>
<p>cd &#8220;$HOME/Library/Application Support/Developer/Shared/XCode/Project Templates/My Templates&#8221;</p>
<p>git clone git://github.com/benellingson/Universal-Navigation-based-Application.git</p>
<p>rm -rf &#8220;Universal-Navigation-based-Application/.git&#8221;
</p></blockquote>
<p><br class="spacer_" /><br />
或者下载zip文件，在创建了目录后，将zip解压其下。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/navigation-based%e5%ba%94%e7%94%a8%e7%a8%8b%e5%ba%8fipad%e6%a8%a1%e6%9d%bf/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>访问外部网页</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e8%ae%bf%e9%97%ae%e5%a4%96%e9%83%a8%e7%bd%91%e9%a1%b5</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e8%ae%bf%e9%97%ae%e5%a4%96%e9%83%a8%e7%bd%91%e9%a1%b5#comments</comments>
		<pubDate>Tue, 10 Aug 2010 01:42:55 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[用户界面]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[提示与技巧]]></category>
		<category><![CDATA[代码片段]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1045</guid>
		<description><![CDATA[实际上有两种方法，第一种是：

1&#91;&#91;UIApplication sharedApplication&#93; openURL:&#91;NSURL URLWithString:@&#34;http://www.google.com&#34;&#93;&#93;;

这种方法将会退出当前程序，用Safari打开url。我有好几个朋友都问到这个问题，实际上非常简单，可以使用UIWebView在当前程序中打开网页（假定你的UIWebView实例为webView）：

12345678910&#160; &#160; &#160;NSString *urlAddress = @&#34;http://localhost&#34;;
&#160; &#160; &#160; &#160; 
&#160; &#160; //Create a URL object.
&#160; &#160; NSURL *url = &#91;NSURL URLWithString:urlAddress&#93;;
&#160; &#160; &#160; &#160; 
&#160; &#160; //URL Requst Object
&#160; &#160; NSURLRequest *requestObj = &#91;NSURLRequest requestWithURL:url&#93;;
&#160; &#160; &#160; &#160; 
&#160; &#160; //Load the request in the UIWebView.
&#160; &#160; &#91;webView loadRequest:requestObj&#93;;
]]></description>
			<content:encoded><![CDATA[<p>实际上有两种方法，第一种是：<br />
<br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>UIApplication sharedApplication<span style="color: #002200;">&#93;</span> openURL<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> URLWithString<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://www.google.com&quot;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div>
<p><br class="spacer_" /><br />
这种方法将会退出当前程序，用Safari打开url。我有好几个朋友都问到这个问题，实际上非常简单，可以使用UIWebView在当前程序中打开网页（假定你的UIWebView实例为webView）：<br />
<br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp;<a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a> <span style="color: #002200;">*</span>urlAddress <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;http://localhost&quot;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">//Create a URL object.</span><br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> <span style="color: #002200;">*</span>url <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/"><span style="color: #400080;">NSURL</span></a> URLWithString<span style="color: #002200;">:</span>urlAddress<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">//URL Requst Object</span><br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/"><span style="color: #400080;">NSURLRequest</span></a> <span style="color: #002200;">*</span>requestObj <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSURLRequest_Class/"><span style="color: #400080;">NSURLRequest</span></a> requestWithURL<span style="color: #002200;">:</span>url<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">//Load the request in the UIWebView.</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>webView loadRequest<span style="color: #002200;">:</span>requestObj<span style="color: #002200;">&#93;</span>;</div></td></tr></tbody></table></div>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e8%ae%bf%e9%97%ae%e5%a4%96%e9%83%a8%e7%bd%91%e9%a1%b5/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>都是Backgrounder惹的祸 &#8211; 解决“越狱”真机调试的问题</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e9%83%bd%e6%98%afbackgrounder%e6%83%b9%e7%9a%84%e7%a5%b8-%e8%a7%a3%e5%86%b3%e2%80%9c%e8%b6%8a%e7%8b%b1%e2%80%9d%e7%9c%9f%e6%9c%ba%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e9%83%bd%e6%98%afbackgrounder%e6%83%b9%e7%9a%84%e7%a5%b8-%e8%a7%a3%e5%86%b3%e2%80%9c%e8%b6%8a%e7%8b%b1%e2%80%9d%e7%9c%9f%e6%9c%ba%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98#comments</comments>
		<pubDate>Sun, 08 Aug 2010 05:07:22 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[调试]]></category>
		<category><![CDATA[Xcode]]></category>
		<category><![CDATA[后台程序]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1038</guid>
		<description><![CDATA[我的iPhone越狱后，在用Xcode进行调试时出现以下错误信息：

warning: Unable to read symbols for &#8220;/Library/MobileSubstrate/DynamicLibraryies/libstatusbar.dylib” (file not found).
Program received singal: &#8220;SIGUSR1&#8243;.

上网查了一下原来是Backgrounder在作怪，最简单的解决方法就是在Backgournder的overrides设定中，禁止要调试的程序以background模式运行即可。

想要知道具体原因，请参见：Backgrounder vs. Build and Run
]]></description>
			<content:encoded><![CDATA[<p>我的iPhone越狱后，在用Xcode进行调试时出现以下错误信息：<br />
<br class="spacer_" /><br />
warning: Unable to read symbols for &#8220;/Library/MobileSubstrate/DynamicLibraryies/libstatusbar.dylib” (file not found).</p>
<p>Program received singal: &#8220;SIGUSR1&#8243;.<br />
<br class="spacer_" /><br />
上网查了一下原来是Backgrounder在作怪，最简单的解决方法就是在Backgournder的overrides设定中，禁止要调试的程序以background模式运行即可。<br />
<br class="spacer_" /><br />
想要知道具体原因，请参见：<a title="Backgrounder vs. Build and Run" href="http://www.alexwhittemore.com/?p=412">Backgrounder vs. Build and Run</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e9%83%bd%e6%98%afbackgrounder%e6%83%b9%e7%9a%84%e7%a5%b8-%e8%a7%a3%e5%86%b3%e2%80%9c%e8%b6%8a%e7%8b%b1%e2%80%9d%e7%9c%9f%e6%9c%ba%e8%b0%83%e8%af%95%e7%9a%84%e9%97%ae%e9%a2%98/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone上通过http传递JSON数据</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iphone%e4%b8%8a%e9%80%9a%e8%bf%87http%e4%bc%a0%e9%80%92json%e6%95%b0%e6%8d%ae</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iphone%e4%b8%8a%e9%80%9a%e8%bf%87http%e4%bc%a0%e9%80%92json%e6%95%b0%e6%8d%ae#comments</comments>
		<pubDate>Fri, 06 Aug 2010 09:03:49 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[编程]]></category>
		<category><![CDATA[网络]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[教程]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=1019</guid>
		<description><![CDATA[

本教程介绍了在iPhone程序中怎样访问JSON web service的详细步骤。


本教程创建了一个简单示例“幸运数字”，它有一个标签，其内容是通过建立于HTTP web service之上的JSON更新的。

源代码/Github

本教程的 源代码 存储于GitHub上。请运行下列命令获取代码：


打开终端程序，改变目录到你希望存储源代码的目录下
输入 git clone  git://github.com/dcgrigsby/luckynumbers.git 获取源代码




iPhone JSON 库

本教程使用了Stig Brautasetd的JSON library (version 2.2)，它提供了解析和生成JSON的功能。在本教程中没有使用生成JSON的功能。

此JSON库提供两种方法解析JSON：(1) 通过category对NSString进行扩展以实现JSON解析 (2) 较为底层一点的基于目标的解析器。本教程从简单方案开始，即方案(1)；在本教程介绍时将介绍方案(2)。


下载 磁盘映像



在稍后的步骤中我们将介绍磁盘映像的使用。

创建项目

启动Xcode 并创建一个新的 View-Based iPhone 程序，命名为  LuckyNumbers:


在Xcode菜单中使用 File &#62; New Project… 创建一个新项目
 在 iPhone OS &#62;  Application 中点取View-Based Application，按下Choose…
将此项目命名为 LuckyNumbers 并按下 Save



为此项目增添JSON支持

要使用JSON功能，我们需要将JSON库加入到项目中：


在项目的 Groups  &#38; Files 面板上展开 LuckyNumbers 项目。
使用Finder，找到你先前下载的 JSON_2.2.dmg 文件，双击加载磁盘映像。带有此DMG内容的另一个新的Finder窗口将打开
将此DMG内容中的 JSON 目录拖入到Xcode [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.mobileorchard.com/wp-content/uploads/2009/03/snap.png" alt="" /><br />
<br class="spacer_" /><br />
本教程介绍了在iPhone程序中怎样访问JSON web service的详细步骤。<br />
<br class="spacer_" /><br />
<span id="more-1019"></span><br />
本教程创建了一个简单示例“幸运数字”，它有一个标签，其内容是通过建立于HTTP web service之上的JSON更新的。<br />
<br class="spacer_" /></p>
<h3>源代码/Github</h3>
<p><br class="spacer_" /><br />
本教程的 <a href="http://github.com/dcgrigsby/luckynumbers">源代码</a> 存储于GitHub上。请运行下列命令获取代码：</p>
<blockquote>
<ol style="font-size: 90%;">
<li>打开终端程序，改变目录到你希望存储源代码的目录下</li>
<li>输入 <em>git clone  git://github.com/dcgrigsby/luckynumbers.git </em>获取源代码<em><br />
</em></li>
</ol>
</blockquote>
<p><br class="spacer_" /></p>
<h3>iPhone JSON 库</h3>
<p><br class="spacer_" /><br />
本教程使用了Stig Brautasetd的<a href="http://code.google.com/p/json-framework/">JSON library</a> (version 2.2)，它提供了解析和生成JSON的功能。在本教程中没有使用生成JSON的功能。<br />
<br class="spacer_" /><br />
此JSON库提供两种方法解析JSON：(1) 通过category对NSString进行扩展以实现JSON解析 (2) 较为底层一点的基于目标的解析器。本教程从简单方案开始，即方案(1)；在本教程介绍时将介绍方案(2)。</p>
<blockquote>
<ol style="font-size: 90%;">
<li><a href="http://code.google.com/p/json-framework/downloads/list">下载</a> 磁盘映像</li>
</ol>
</blockquote>
<p><br class="spacer_" /><br />
在稍后的步骤中我们将介绍磁盘映像的使用。<br />
<br class="spacer_" /></p>
<h3>创建项目</h3>
<p><br class="spacer_" /><br />
启动Xcode 并创建一个新的 View-Based iPhone 程序，命名为  LuckyNumbers:</p>
<blockquote>
<ol style="font-size: 90%;">
<li>在Xcode菜单中使用 <em>File &gt; New Project…</em> 创建一个新项目</li>
<li><em> </em>在 <em>iPhone OS &gt;  Application</em> 中点取<em>View-Based Application，</em>按下<em>Choose…</em></li>
<li>将此项目命名为 <em>LuckyNumbers</em> 并按下 <em>Save</em></li>
</ol>
</blockquote>
<p><br class="spacer_" /></p>
<h3>为此项目增添JSON支持</h3>
<p><br class="spacer_" /><br />
要使用JSON功能，我们需要将JSON库加入到项目中：</p>
<blockquote>
<ol style="font-size: 90%;">
<li>在项目的<em> Groups  &amp; Files</em> 面板上展开 <em>LuckyNumbers</em> 项目。</li>
<li>使用Finder，找到你先前下载的 <em>JSON_2.2.dmg</em> 文件，双击加载磁盘映像。带有此DMG内容的另一个新的Finder窗口将打开</li>
<li>将此DMG内容中的 <em>JSON</em> 目录拖入到Xcode <em>Groups  &amp; Files </em>面板中<em>LuckyNumbers</em> 项目图标下的<em>Classes</em> 文件夹中</li>
</ol>
</blockquote>
<p><br class="spacer_" /><br />
为测试JSON库是否正确设置，我们将解析一个JSON字典字符串，并在console中输出其结果NSDictionary。此功能是在<em>viewDidLoad</em>中完成。<br />
<br class="spacer_" /><br />
在 LuckyNumbersViewController.m 中加入如下代码：</p>
<pre>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#import &quot;LuckyNumbersViewController.h&quot;<br />
#import &quot;JSON/JSON.h&quot;<br />
<br />
@implementation LuckyNumbersViewController<br />
<br />
- (void)viewDidLoad {<br />
&nbsp; &nbsp; [super viewDidLoad];<br />
&nbsp; &nbsp; NSString *jsonString = [NSString stringWithString:@&quot;{\&quot;foo\&quot;: \&quot;bar\&quot;}&quot;];<br />
&nbsp; &nbsp; NSDictionary *dictionary = [jsonString JSONValue];<br />
&nbsp; &nbsp; NSLog(@&quot;Dictionary value for \&quot;foo\&quot; is \&quot;%@\&quot;&quot;, [dictionary objectForKey:@&quot;foo&quot;]);<br />
}<br />
<br />
- (void)dealloc {<br />
&nbsp; &nbsp; [super dealloc];<br />
}<br />
<br />
@end</div></td></tr></tbody></table></div>
</pre>
<p><br class="spacer_" /><br />
运行项目。如果 JSON SDK 设置正确的话，你应该将在console中见到如下信息：“ <em>Dictionary value  for “foo” is “bar” ”</em>.<br />
<br class="spacer_" /></p>
<h3>简单UI设置</h3>
<p><br class="spacer_" /><br />
我们最终成品是使用 UILabel 来显示通过HTTP 和 JSON 获取的幸运数字。<br />
<br class="spacer_" /><br />
在 LuckyNumbersViewController.h 使用如下代码：</p>
<pre>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#import &lt;UIKit/UIKit.h&gt;<br />
<br />
@interface LuckyNumbersViewController : UIViewController {<br />
&nbsp; &nbsp; IBOutlet UILabel *label;<br />
}<br />
<br />
@end</div></td></tr></tbody></table></div>
</pre>
<p><br class="spacer_" /><br />
<em>IBOutlet</em> 是一个宏，它通知编译器将变量与通过Interface Builder 的WYSIWYG添加的UILabel元件联系起来。下一步我们将添加元件并将这两部分连接起来。<br />
<br class="spacer_" /><br />
在Interface Builder中编辑 LuckyNumbersViewController.xib 文件：</p>
<blockquote>
<ol style="font-size: 90%;">
<li>在<em>Groups &amp; Files</em>中展开<em>LuckyNumbers</em>下的 <em>Resources</em> 文件夹。</li>
<li>双击 <em>LuckyNumbersViewController.xib</em> 文件。</li>
</ol>
</blockquote>
<p><br class="spacer_" /><br />
确保 Library, Inspector 和 View 窗口都打开/可见。如果没有的话：</p>
<blockquote>
<ol style="font-size: 90%;">
<li>在菜单中使用 <em>Tools &gt; Library</em> 显示 Library 窗口</li>
<li>在菜单中使用 <em>Tools &gt; Inspector</em> 显示 Inspector 窗口</li>
<li>在 <em>LuckyNumbersViewController.xib</em> 窗口中点击 View 图标</li>
</ol>
</blockquote>
<p><br class="spacer_" /><br />
添加一个label:</p>
<blockquote>
<ol style="font-size: 90%;">
<li>在<em>Library </em>窗口中找到 <em>Label</em> 元件并拖入view</li>
<li>在 <em>View </em>窗口中将 label 放大到整个view的一半</li>
<li>在 <em>Inspector </em> 窗口中的 <em>View Attributes</em>下 , 将 label 的行数设为0。</li>
</ol>
</blockquote>
<p><br class="spacer_" /><br />
将 label 行数设为0表示lable的尺寸在其指定的边界内动态可变。<br />
<br class="spacer_" /><br />
连接 Interface Builder 中的 label 到代码 <em>label</em>。   仍然在 Interface Builder 中:</p>
<blockquote>
<ol style="font-size: 90%;">
<li>Control + 点击<em>LuckyNumbersViewController.xib</em> 窗口中的 <em>File’s Owner</em> 图标</li>
<li>在弹出菜单中，点击并按住<em>Outlets</em> 部分 lable 行右方的圆圈</li>
<li>拖动鼠标到View中的 <em>Label</em> 上。 将出现一条蓝线连接这两个部分。</li>
</ol>
</blockquote>
<p><br class="spacer_" /><br />
这两个部分连接后，弹出菜单将如图所示。<br />
<br class="spacer_" /><br />
<img src="http://www.mobileorchard.com/wp-content/uploads/2009/03/connection.png" alt="" /><br />
<br class="spacer_" /><br />
如果一切正常的话，保存并关闭Interface  Builder。<br />
<br class="spacer_" /></p>
<h3>通过HTTP获取 JSON 数据</h3>
<p><br class="spacer_" /><br />
我们将使用 Cocoa 中的 NSURLConnection 来发送一个 HTTP 请求从而获取 JSON 数据。<br />
<br class="spacer_" /><br />
Cocoa 在进行HTTP请求时有两种选项：同步和异步。同步请求中程序的主runloop中运行，使得在请求的过程中，程序停止运行。而异步请求使用回调来避免程序锁住而且简单易用。因此我们使用异步请求。<br />
<br class="spacer_" /><br />
首先我们需要修改视图控制器接口，创建一个<em>NSMutableData</em>变量来保存响应数据。我们在接口（.h）中而不是在方法中定义此变量是因为响应数据是逐步的而不是一次性返回的，我们需要将所有数据组合在一起。<br />
<br class="spacer_" /><br />
修改 LuckNumbersViewController.h。改变如下黑体所示：</p>
<pre>#import &lt;UIKit/UIKit.h&gt;

@interface LuckyNumbersViewController : UIViewController {
	IBOutlet UILabel *label;
	<strong>NSMutableData *responseData;</strong>
}</pre>
<p><br class="spacer_" /><br />
简单起见，我们在 <em>viewDidLoad</em>中进行HTTP请求。<br />
<br class="spacer_" /><br />
修改 LuckyNumbersViewController.m :</p>
<pre>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">#import &quot;LuckyNumbersViewController.h&quot;<br />
#import &quot;JSON/JSON.h&quot;<br />
<br />
@implementation LuckyNumbersViewController<br />
<br />
- (void)viewDidLoad {<br />
&nbsp; &nbsp; [super viewDidLoad];<br />
<br />
&nbsp; &nbsp; responseData = [[NSMutableData data] retain];<br />
&nbsp; &nbsp; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@&quot;http://www.unpossible.com/misc/lucky_numbers.json&quot;]];<br />
&nbsp; &nbsp; [[NSURLConnection alloc] initWithRequest:request delegate:self];<br />
}<br />
<br />
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {<br />
&nbsp; &nbsp; [responseData setLength:0];<br />
}<br />
<br />
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {<br />
&nbsp; &nbsp; [responseData appendData:data];<br />
}<br />
<br />
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {<br />
&nbsp; &nbsp; label.text = [NSString stringWithFormat:@&quot;Connection failed: %@&quot;, [error description]];<br />
}<br />
<br />
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {<br />
&nbsp; &nbsp; [connection release];<br />
}<br />
<br />
- (void)dealloc {<br />
&nbsp; &nbsp; [super dealloc];<br />
}<br />
<br />
@end</div></td></tr></tbody></table></div>
</pre>
<p><br class="spacer_" /><br />
responseData 变量用来存放数据，然后在  viewDidload中进行HTTP连接;  <em>didReceiveData</em>用来收集返回的数据; 空白的 connectionDidFinishLoading 表示数据响应结束。<br />
<br class="spacer_" /></p>
<h3>使用 JSON 数据</h3>
<p><br class="spacer_" /><br />
下面我们将展示怎样在 connectionDidFinishLoading 中对获取的 JSON 数据的进行处理。<br />
<br class="spacer_" /><br />
修改LuckyNumbersViewController.m中的 connectionDidFinishLoading 方法。使用下面代码：</p>
<pre>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">- (void)connectionDidFinishLoading:(NSURLConnection *)connection {<br />
&nbsp; &nbsp; [connection release];<br />
<br />
&nbsp; &nbsp; NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];<br />
&nbsp; &nbsp; [responseData release];<br />
<br />
&nbsp; &nbsp; NSArray *luckyNumbers = [responseString JSONValue];<br />
<br />
&nbsp; &nbsp; NSMutableString *text = [NSMutableString stringWithString:@&quot;Lucky numbers:\n&quot;];<br />
<br />
&nbsp; &nbsp; for (int i = 0; i &amp;lt; [luckyNumbers count]; i++)<br />
&nbsp; &nbsp; &nbsp; &nbsp; [text appendFormat:@&quot;%@\n&quot;, [luckyNumbers objectAtIndex:i]];<br />
<br />
&nbsp; &nbsp; label.text = &nbsp;text;<br />
}</div></td></tr></tbody></table></div>
</pre>
<p><br class="spacer_" /><br />
本文最开始的示例代码中使用了 NSDictionary。而现在我们使用 NSArray。 解析器非常灵活，其返回对象 &#8211; 包括嵌套对象 &#8211; 将 JSON数据类型与Objective-C的数据类型很好地匹配起来。<br />
<br class="spacer_" /></p>
<h3>更好的错误处理</h3>
<p><br class="spacer_" /><br />
至此我们使用了NSString扩展的方法对JSON数据进行了解析。这样做是非常简单的。<br />
<br class="spacer_" /><br />
但不幸的是，使用此方法是错误处理变得很困难。如果JSON解析器因为某种原因失败的话，它仅仅返回一个nil值。但是如果错误发生时你观察console，你就会发现一些信息描述了引擎解析器失败的原因。<br />
<br class="spacer_" /><br />
如果我们能将详细错误信息传递给用户，那将更加用户友好。要达到这个目的，我们将切换到JSON SDK支持的第二种面向对象的方法。<br />
<br class="spacer_" /><br />
修改LuckyNumbersViewController.m中<em>connectionDidFinishLoading</em> 方法。使用下面代码：</p>
<div class="codecolorer-container text mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">- (void)connectionDidFinishLoading:(NSURLConnection *)connection {<br />
&nbsp; &nbsp; [connection release];<br />
<br />
&nbsp; &nbsp; NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];<br />
&nbsp; &nbsp; [responseData release];<br />
<br />
&nbsp; &nbsp; NSError *error;<br />
&nbsp; &nbsp; SBJSON *json = [[SBJSON new] autorelease];<br />
&nbsp; &nbsp; NSArray *luckyNumbers = [json objectWithString:responseString error:&amp;error];<br />
&nbsp; &nbsp; [responseString release]; &nbsp; <br />
<br />
&nbsp; &nbsp; if (luckyNumbers == nil)<br />
&nbsp; &nbsp; &nbsp; &nbsp; label.text = [NSString stringWithFormat:@&quot;JSON parsing failed: %@&quot;, [error localizedDescription]];<br />
&nbsp; &nbsp; else {<br />
&nbsp; &nbsp; &nbsp; &nbsp; NSMutableString *text = [NSMutableString stringWithString:@&quot;Lucky numbers:\n&quot;];<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i &lt;; [luckyNumbers count]; i++)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [text appendFormat:@&quot;%@\n&quot;, [luckyNumbers objectAtIndex:i]];<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; label.text = &nbsp;text;<br />
&nbsp; &nbsp; }<br />
}</div></td></tr></tbody></table></div>
</pre>
<p><br class="spacer_" /><br />
使用此方法可以帮助我们在JSON解析器发生错误时指出错误所在以便进行更好的错误处理。<br />
<br class="spacer_" /></p>
<h3>结论</h3>
<p><br class="spacer_" /><br />
JSON SDK 和 Cocoa 固有的 HTTP功能使得在iPhone应用程序中运用JSON web service变得非常容易。<br />
<br class="spacer_" /><br />
原文见：<a href="http://www.mobileorchard.com/tutorial-json-over-http-on-the-iphone/">Tutorial: JSON Over HTTP On The iPhone</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iphone%e4%b8%8a%e9%80%9a%e8%bf%87http%e4%bc%a0%e9%80%92json%e6%95%b0%e6%8d%ae/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IAP（程序内购买）: 完全攻略</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iap%ef%bc%88%e7%a8%8b%e5%ba%8f%e5%86%85%e8%b4%ad%e4%b9%b0%ef%bc%89-%e5%ae%8c%e5%85%a8%e6%94%bb%e7%95%a5</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iap%ef%bc%88%e7%a8%8b%e5%ba%8f%e5%86%85%e8%b4%ad%e4%b9%b0%ef%bc%89-%e5%ae%8c%e5%85%a8%e6%94%bb%e7%95%a5#comments</comments>
		<pubDate>Mon, 02 Aug 2010 06:20:40 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[基础]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[In-App Purchase]]></category>
		<category><![CDATA[教程]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=992</guid>
		<description><![CDATA[
第一印象觉得In-App Purchase（简称IAP）非常简单。Apple提供的大量文档应该让开发者很快熟悉地熟悉。那么，为什么在你的应用中集成IAP特性就如此令人生厌呢？

这是因为在开发过程中不可避免会出现一些错误。而但这些错误发生的时候，你就抓瞎了。虽然Apple提供了有关IAP的大量文档，但他们并未提及集成IAP的详细步骤。而且对StoreKit集成过程中出现的问题也没有一个核对清单。另外对于为什么诸如产品ID非法之类的问题也没有提供NSError之类的对象来告诉你原因。

在试用了各种可能的解决方案后，你只能身心疲惫，彷徨无助。

为了提高你的效率和减少你的痛苦，我觉定利用此文来介绍一下实现IAP的详细步骤。本文很详细，有点长。甚至可能太长了，但不像Apple的文档，它提供了为实现IAP的每一个步骤。

废话少说，我们直入主题吧。


概况

IAP能正常工作的秘诀：分成两个步骤：

创建及提取产品描述
购买产品


第一个步骤是你可能遇到问题的部分。一旦你在代码中成功地获取了产品描述，编写购买产品的代码不过是小菜一碟。

我们先看看步骤1。

创建及提取产品描述

下面是有关创建产品及提取其描述的非常粗略的步骤：

创建唯一的App ID
生成及安装新的provisioning profile文件
在Xcode中更新 bundle ID 及 code signing profile
如果还没做的话，请在iTunes Connect中提交有关你程序的 metadata
如果还没做的话，请在iTunes Connect中提交你程序的二进制码
为IAP添加新产品
编写提取产品描述的代码
等待几小时


提取产品描述的代码非常简单，但其他步骤则很容易错。
注意： 为提取产品描述，你并不需要在iTunes Connect中创建IAP测试用户。

 
1. 创建唯一的App ID

为支持IAP，你的App ID不能包括通配符（“*”）。为确定你的App Id是否包括通配符，请登录http://developer.apple.com/iphone,在 iPhone Developer Program Portal中选择左边菜单中的 “App IDs”检查你的 App ID。

下面是一个唯一的App ID:
7DW89RZKLY.com.runmonster.runmonsterfree

下面不是一个唯一的 App ID:
7DW89RZKLY.com.runmonster.*

如果你还没有一个唯一的App ID，按如下步骤创建一个：

在developer portal中的 App IDs 部分，选择“New App ID”
填写下列信息：

Display name（显示名）: 选取一个不同的App ID的名称。你不能编辑或删除旧的App ID，所以你必须为你的App ID提供一个新名称以避免混淆。
Prefix（前缀）: 生成一个新的前缀，或者如果你的程序是通过Keychain Services API分享数据的系列程序中之一的话，则选用已存在的前缀。
Suffix（后缀）: com.companyname.appname (这是通用格式 &#8211; 注意没有使用通配符）。


按 “Save”
按 App ID旁的“Configure” 链接
选取 “Enable [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>第一印象觉得In-App Purchase（简称IAP）非常简单。Apple提供的<a href="http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction/Introduction.html">大量</a><a href="https://itunesconnect.apple.com/docs/iTunesConnect_DeveloperGuide.pdf">文档</a>应该让开发者很快熟悉地熟悉。那么，为什么在你的应用中集成IAP特性就如此令人生厌呢？</p>
<p><br class="spacer_" /></p>
<p>这是因为在开发过程中不可避免会出现一些错误。而但这些错误发生的时候，你就抓瞎了。虽然Apple提供了有关IAP的大量文档，但他们并未提及集成IAP的详细步骤。而且对StoreKit集成过程中出现的问题也没有一个核对清单。另外对于为什么诸如产品ID非法之类的问题也没有提供NSError之类的对象来告诉你原因。</p>
<p><br class="spacer_" /></p>
<p>在试用了各种可能的解决方案后，你只能身心疲惫，彷徨无助。</p>
<p><br class="spacer_" /></p>
<p>为了提高你的效率和减少你的痛苦，我觉定利用此文来介绍一下实现IAP的详细步骤。本文很详细，有点长。甚至可能太长了，但不像Apple的文档，它提供了为实现IAP的每一个步骤。</p>
<p><br class="spacer_" /></p>
<p>废话少说，我们直入主题吧。</p>
<p><br class="spacer_" /></p>
<p><span id="more-992"></span></p>
<h2><strong>概况</strong></h2>
<p><br class="spacer_" /></p>
<p>IAP能正常工作的秘诀：分成两个步骤：</p>
<ol>
<li>创建及提取产品描述</li>
<li>购买产品</li>
</ol>
<p><br class="spacer_" /></p>
<p>第一个步骤是你可能遇到问题的部分。一旦你在代码中成功地获取了产品描述，编写购买产品的代码不过是小菜一碟。</p>
<p><br class="spacer_" /></p>
<p>我们先看看步骤1。</p>
<p><br class="spacer_" /></p>
<h2>创建及提取产品描述</h2>
<p><br class="spacer_" /></p>
<p>下面是有关创建产品及提取其描述的非常粗略的步骤：</p>
<ol>
<li>创建唯一的App ID</li>
<li>生成及安装新的provisioning profile文件</li>
<li>在Xcode中更新 bundle ID 及 code signing profile</li>
<li>如果还没做的话，请在iTunes Connect中提交有关你程序的 metadata</li>
<li>如果还没做的话，请在iTunes Connect中提交你程序的二进制码</li>
<li>为IAP添加新产品</li>
<li>编写提取产品描述的代码</li>
<li>等待几小时</li>
</ol>
<p><br class="spacer_" /></p>
<p>提取产品描述的代码非常简单，但其他步骤则很容易错。</p>
<p><em><strong>注意：</strong> 为提取产品描述，你并<strong>不</strong>需要</em><em>在iTunes Connect中</em><em>创建IAP测试用户。</em></p>
<p><em><br />
 </em></p>
<h3>1. 创建唯一的App ID</h3>
<p><br class="spacer_" /></p>
<p>为支持IAP，你的App ID不能包括通配符（“*”）。为确定你的App Id是否包括通配符，请登录<a href="http://developer.apple.com/iphone">http://developer.apple.com/iphone</a>,在 iPhone Developer Program Portal中选择左边菜单中的 “App IDs”检查你的 App ID。</p>
<p><br class="spacer_" /></p>
<p>下面是一个唯一的App ID:</p>
<p>7DW89RZKLY.com.runmonster.runmonsterfree</p>
<p><br class="spacer_" /></p>
<p>下面<strong>不</strong>是一个唯一的 App ID:</p>
<p>7DW89RZKLY.com.runmonster.*</p>
<p><br class="spacer_" /></p>
<p>如果你还没有一个唯一的App ID，按如下步骤创建一个：</p>
<ol>
<li>在developer portal中的 App IDs 部分，选择“New App ID”</li>
<li>填写下列信息：
<ul>
<li><strong>Display name（显示名）</strong>: 选取一个不同的App ID的名称。你不能编辑或删除旧的App ID，所以你必须为你的App ID提供一个新名称以避免混淆。</li>
<li><strong>Prefix（前缀）</strong>: 生成一个新的前缀，或者如果你的程序是<a href="http://developer.apple.com/iphone/library/samplecode/GenericKeychain/index.html">通过Keychain Services API分享数据</a>的系列程序中之一的话，则选用已存在的前缀。<a href="http://developer.apple.com/iphone/library/samplecode/GenericKeychain/index.html"></a></li>
<li><strong>Suffix（后缀）</strong>: <em>com.companyname.appname</em> (这是通用格式 &#8211; 注意没有使用通配符）。</li>
</ul>
</li>
<li>按 “Save”</li>
<li>按 App ID旁的“Configure” 链接</li>
<li>选取 “Enable In App Purchase”选择框</li>
<li>按“Done”</li>
</ol>
</div>
<div>
<p><br class="spacer_" /></p>
<h3>2. 创建一个新的Provisioning Profile文件</h3>
<p><br class="spacer_" /></p>
<p>在创建了新的App ID后,你需要生成一个指向这个App ID的新provisioning profile。</p>
<p><br class="spacer_" /></p>
<p>下面就是令人痛苦的生成和安装新provisioning profile的详细步骤:</p>
<ol>
<li>在 iPhone Developer Portal中, 选择左边的Provisioning部分</li>
<li>确保你处于Development 标签下, 按下右上角的 “New Profile”</li>
<li>填入所需信息并指向你刚创建的唯一的App ID</li>
<li>如果你在Actions条目下看到 “Pending”，那么请按下“Development”标签标题进行刷新</li>
<li>点击 “Download” 下载新的profile文件</li>
<li>将profile文件拖入到Dock中Xcode图标上进行安装</li>
<li>如果你想在硬盘上保存provisioning  profile，那么你可以按如下步骤手工安装profile：
<ol style="list-style-type: decimal;">
<li>在Xcode中, 选择 Window > Organizer </li>
<li>选择左边 “Provisioning Profiles” 分类</li>
<li>Ctrl-按下profile > Reveal in Finder </li>
<li>将新profile拖入到 profile Finder 窗口</li>
</ol>
</li>
</ol>
</div>
<div>
<p><br class="spacer_" /></p>
<h3></h3>
<h3>3. 更新Xcode 设置</h3>
<p><br class="spacer_" /></p>
<p>在Xcode中安装了 profile 文件后，你需要对使用此provisiong profile的项目进行一些编辑工作：</p>
<ol>
<li>编辑项目 .plist 文件使其 Bundle ID 与  App ID 匹配。忽略ID开始部分的字母数字序列。例如，在Developer Portal中你的App ID为“7DW89RZKLY.com.runmonster.runmonsterfree”，那么在Bundle ID中你只需输入“com.runmonster.runmonsterfree” 。</li>
<li>编辑项目的 target 信息以使用新的provisioning profile:
<ol style="list-style-type: decimal;">
<li>选取 Project > Edit Active Target </li>
<li>选取顶部“Build” 标签</li>
<li>选取需要的 configuration (通常为 Debug) </li>
<li>在<strong>Code  Signing Identity</strong>中选择新的provisioning profile </li>
<li>在<strong>Code Signing Identity</strong>之下的行中(可能名为 <strong>Any iPhone OS Device</strong>)选择新的provisioning profile</li>
</ol>
</li>
</ol>
</div>
<div>
<p><br class="spacer_" /></p>
<h3>4. 添加你的应用程序</h3>
<p><br class="spacer_" /></p>
<p>如果你的程序已经发表到App Store了，那么可以略过此步骤。</p>
<p><br class="spacer_" /></p>
<p>在你将产品添加到 iTunes Connect之前，你必须添加此产品所需的程序。如果你的程序还没有100%完成也无需担心，你可以先提交具有部分数据的程序，最后再提交真实的程序。</p>
<p><br class="spacer_" /></p>
<p><em><strong>注意</strong>: 只有 SKU 和 version（版本）部分是以后不可修改的</em></p>
<ol>
<li>登录到 <a href="http://developer.apple.com/iphone">http://developer.apple.com/iphone</a></li>
<li>点击右边链接进入 iTunes Connect
<ul>
<li><em>注意：你<strong>必须</strong>先登录到developer.apple.com，否则会有不测发生（译者注：具体是什么不测我也不太清楚，胆大的请自己试一下）</em></li>
</ul>
</li>
<li>在 iTunes Connect主页点击 “Manage Your  Applications” </li>
<li>在右上角点击“Create New Application”</li>
<li>填写程序所需的一切信息。当要求程序二进制码时，请选择稍后上传选项。</li>
</ol>
</div>
<div>
<p><br class="spacer_" /></p>
<h3>5. 提交程序二进制码</h3>
<p><br class="spacer_" /></p>
<p>Apple的文档中没有任何地方提及详情，但它却是必须的步骤。要成功测IAP功能，你<strong>必须</strong>提交程序的二进制码。即使你的程序还没有100%完成，你仍然需要提交二进制码。然而，你也可以立即摈弃你的二进制码，使其不会进入审核阶段。</p>
<p><br class="spacer_" /></p>
<p>下面这些步骤非常关键，我可是因为少做了某些步骤而度过了一段非常痛苦的时间：</p>
<ol>
<li>生成App Store发布版程序
<ul>
<li>如果你不知怎么做，请在 iPhone Developer Portal 中点击左方的 Distribution标签，并选择  “Prepare App” 标签。然后，根据蓝色链接的指示：
<ul>
<li>获取iPhone发行许可证</li>
<li>创建并下载在App Store发行所需的iPhone Distribution Provisioning Profile</li>
<li>在Xcode中生成程序的发行版</li>
</ul>
</li>
</ul>
</li>
<li>在iTunes Connect中进入程序页</li>
<li>选择 “Upload Binary”</li>
<li>上传.zip压缩程序</li>
<li>如果你的程序还没有100%完成以进行审核，那么请点击iTunes Connect中你程序首页中的  “Reject Binary”链接。程序的状态应该更新为 “Developer Rejected”.</li>
</ol>
<p><br class="spacer_" /></p>
<p>不用担心，由于程序的状态是“Developer Rejected”，Apple是不会对其进行审核的。你可以在任何时候提交程序的新版本并使其状态为“Developer Rejected”，这不会对以后程序正式提交的等待时间有任何影响。</p>
<p><br class="spacer_" /></p>
<h3>6. 添加产品</h3>
<p><br class="spacer_" /></p>
<p>完成了以上所有步骤后，我们最终可以向iTunes Connect中添加产品了。</p>
<ol>
<li>确保登录到 <a href="http://developer.apple.com/iphone">http://developer.apple.com/iphone</a></li>
<li>进入 iTunes Connect 主页</li>
<li>点击 “Manage Your in App Purchases” 链接</li>
<li>点击 “Create New”</li>
<li>选择你的程序</li>
<li>填写下列产品信息：
<ul>
<li><strong>Reference Name（参考名称）</strong>: 产品的通用名称。比如，我使用的是  “Pro Upgrade”。此名称是不允许进行编辑的，它不会显示于App Store中。</li>
<li><strong>Product ID（产品ID）</strong>: 你产品的唯一id。通常格式是 <em>com.company.appname.product</em>，但它可以说任何形式。它并不要求以程序的App ID作为前缀。</li>
<li><strong>Type（类型）</strong>: 有三种选择
<ul>
<li><strong>Non-consumable（非消耗品）</strong>: 仅需付费一次 (例如你希望将出现从免费版升级为专业版）</li>
<li><strong>Consumable（消耗品）</strong>: 每次下载都需要付费</li>
<li><strong>Subscription（预订）</strong>: 循环反复</li>
</ul>
</li>
<li><strong>Price Tier（价格等级）</strong>: 产品价格。参见不同等级的价格列表。</li>
<li><strong>Cleared for Sale（等待销售）</strong>: 一定要选取此项，否则的话，测试时会发生非法产品ID的错误。</li>
<li><strong>Language to Add（增加的语言）</strong>:  选一项。下列两项将出现：
<ul>
<li><strong>Displayed Name（显示名称）</strong>: 用户看到的产品名称。比如我选择 “Upgrade to Pro”。</li>
<li><strong>Description（描述）</strong>: 对产品进行描述。此处输入的文本将与Displayed Name 及 Price 一起在你代码中提取 SKProduct时出现。</li>
</ul>
</li>
<li><strong>Screenshot（截屏）</strong>: 展示你产品的截屏。尽管屏幕上会显示“提交截屏会触发产品审核过程”之类的文字（个人拙见，这是非常糟糕的设计），你还是可以安全地提交截屏而不会使产品进入审核过程。存储后，选择“Submit  with app binary” （随程序二进制码一起提交）选项。是产品与程序二进制绑定在一起，所以在你最后正式提交100%完成的程序二进制码时，产品也会随之提交。</li>
</ul>
</li>
<li>点击 “Save”</li>
</ol>
</div>
<div>
<p><br class="spacer_" /></p>
<h3>7. 编写代码</h3>
<p><br class="spacer_" /></p>
<p>下面我们开始编写代码对刚加入到iTunes Connect中的产品信息进行提取。我访问产品数据，我们需要使用 StoreKit framework。</p>
<p><br class="spacer_" /></p>
<p><em>注意： StoreKit 无法在模拟器上工作。你必须在真机上进行测试。</em></p>
<ol>
<li>1.添加 StoreKit framework 到你的项目中。</li>
<li>2.添加SKProduct引用到你的 .h 文件中：</li>
</ol>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// InAppPurchaseManager.h</span><br />
<br />
<span style="color: #6e371a;">#import &lt;StoreKit/StoreKit.h&gt;</span><br />
<br />
<span style="color: #6e371a;">#define kInAppPurchaseManagerProductsFetchedNotification @&quot;kInAppPurchaseManagerProductsFetchedNotification&quot;</span><br />
<br />
<span style="color: #a61390;">@interface</span> InAppPurchaseManager <span style="color: #002200;">:</span> <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/"><span style="color: #400080;">NSObject</span></a> &lt;SKProductsRequestDelegate&gt;<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; SKProduct <span style="color: #002200;">*</span>proUpgradeProduct;<br />
&nbsp; &nbsp; SKProductsRequest <span style="color: #002200;">*</span>productsRequest;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p><em>注意: InAppPurchaseManager 是一个单例类，它处理程序中所有IAP任务。它是本文中的示例程序。</em></p>
<ol>
<li>3.产品请求，并在相应.m文件中实现代理协议：</li>
</ol>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// InAppPurchaseManager.m</span><br />
<br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>requestProUpgradeProductData<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSSet_Class/"><span style="color: #400080;">NSSet</span></a> <span style="color: #002200;">*</span>productIdentifiers <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSSet_Class/"><span style="color: #400080;">NSSet</span></a> setWithObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;com.runmonster.runmonsterfree.upgradetopro&quot;</span> <span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; productsRequest <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>SKProductsRequest alloc<span style="color: #002200;">&#93;</span> initWithProductIdentifiers<span style="color: #002200;">:</span>productIdentifiers<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; productsRequest.delegate <span style="color: #002200;">=</span> self;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>productsRequest start<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// we will release the request object in the delegate callback</span><br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #6e371a;">#pragma mark -</span><br />
<span style="color: #6e371a;">#pragma mark SKProductsRequestDelegate methods</span><br />
<br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>productsRequest<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKProductsRequest <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>request didReceiveResponse<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKProductsResponse <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>response<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/"><span style="color: #400080;">NSArray</span></a> <span style="color: #002200;">*</span>products <span style="color: #002200;">=</span> response.products;<br />
&nbsp; &nbsp; proUpgradeProduct <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>products count<span style="color: #002200;">&#93;</span> <span style="color: #002200;">==</span> 1 ? <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>products firstObject<span style="color: #002200;">&#93;</span> retain<span style="color: #002200;">&#93;</span> <span style="color: #002200;">:</span> <span style="color: #a61390;">nil</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>proUpgradeProduct<span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Product title: %@&quot;</span> , proUpgradeProduct.localizedTitle<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Product description: %@&quot;</span> , proUpgradeProduct.localizedDescription<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Product price: %@&quot;</span> , proUpgradeProduct.price<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Product id: %@&quot;</span> , proUpgradeProduct.productIdentifier<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a> <span style="color: #002200;">*</span>invalidProductId <span style="color: #a61390;">in</span> response.invalidProductIdentifiers<span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Invalid product id: %@&quot;</span> , invalidProductId<span style="color: #002200;">&#41;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// finally release the reqest we alloc/init’ed in requestProUpgradeProductData</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>productsRequest release<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/"><span style="color: #400080;">NSNotificationCenter</span></a> defaultCenter<span style="color: #002200;">&#93;</span> postNotificationName<span style="color: #002200;">:</span>kInAppPurchaseManagerProductsFetchedNotification object<span style="color: #002200;">:</span>self userInfo<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>上面代码有几点需要注意：</p>
<ul>
<li>指定产品id时，你必须使用完整产品id。例如，上例中使用 “com.runmonster.runmonsterfree.upgradetopro”。仅使用 “upgradetopro” 将不会正常工作。</li>
<li>如果在productsRequest:didReceiveResponse:中response.products 为 nil，而你的产品id出现于 response.invalidProductIdentifers 数组中时，那么请做好心理准备开始一场徒劳的搜索战吧。 StoreKit API没有提供任何帮助，也没有任何指示关于为什么你的id是无效的。很可爱，不是吗？</li>
<li>SKProduct类提供了有关程序标题和描述的本地化版本，但是价格则没有本地化版本。下面是针对此疏忽提供的代码：</li>
</ul>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// SKProduct+LocalizedPrice.h</span><br />
<br />
<span style="color: #6e371a;">#import &lt;Foundation/Foundation.h&gt;</span><br />
<span style="color: #6e371a;">#import &lt;StoreKit/StoreKit.h&gt;</span><br />
<br />
<span style="color: #a61390;">@interface</span> SKProduct <span style="color: #002200;">&#40;</span>LocalizedPrice<span style="color: #002200;">&#41;</span><br />
<br />
<span style="color: #a61390;">@property</span> <span style="color: #002200;">&#40;</span>nonatomic, readonly<span style="color: #002200;">&#41;</span> <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a> <span style="color: #002200;">*</span>localizedPrice;<br />
<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// SKProduct+LocalizedPrice.m</span><br />
<br />
<span style="color: #6e371a;">#import &quot;SKProduct+LocalizedPrice.h&quot;</span><br />
<br />
<span style="color: #a61390;">@implementation</span> SKProduct <span style="color: #002200;">&#40;</span>LocalizedPrice<span style="color: #002200;">&#41;</span><br />
<br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>localizedPrice<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumberFormatter_Class/"><span style="color: #400080;">NSNumberFormatter</span></a> <span style="color: #002200;">*</span>numberFormatter <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNumberFormatter_Class/"><span style="color: #400080;">NSNumberFormatter</span></a> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>numberFormatter setFormatterBehavior<span style="color: #002200;">:</span>NSNumberFormatterBehavior10_4<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>numberFormatter setNumberStyle<span style="color: #002200;">:</span>NSNumberFormatterCurrencyStyle<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>numberFormatter setLocale<span style="color: #002200;">:</span>self.priceLocale<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a> <span style="color: #002200;">*</span>formattedString <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>numberFormatter stringFromNumber<span style="color: #002200;">:</span>self.price<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>numberFormatter release<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> formattedString;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>加入上述代码，测试一下。你应该在控制台窗口中看见产品信息了。然而更大的可能是，你得到了一个无效的产品id。我下一篇<a href="无效产品id的处理方法">文章</a>将介绍怎样对这个问题进行调试。但是，下面的步骤8有可能是阻碍你前进的障碍。</p>
<p><br class="spacer_" /></p>
<h3>8. 等待几小时</h3>
<p><br class="spacer_" /></p>
<p>遵循了上述所有步骤，但是你的产品仍然是无效的？你是否两次，三次，四次不懈努力地确认你是否遵循了上面提到的每个步骤？你是否已经对网上IAP信息少得可怜而感到绝望？</p>
<p><br class="spacer_" /></p>
<p>那么，你应该等待。</p>
<p><br class="spacer_" /></p>
<p>你的产品要进入iTunes Connect使得Apple准备好沙箱环境需要一些时间。对于我而言，我是经过了无数次产品无效错误的绝望。而在24小时后，我没有修改任何一行代码，但产品id变为有效。我认为要使产品发布到Apple的网络系统需要几个小时的时间，但如果你有时间的话，你可以像我一样等上24个小时。</p>
<p><br class="spacer_" /></p>
<h2>购买产品</h2>
<p><br class="spacer_" /></p>
<p>至此你应该已经成功地获取了 SKProduct 描述。比较而言，支持购买产品相对简单些。仅需下面三个步骤：</p>
<ol>
<li>编写代码支持事务（transaction）</li>
<li>在iTunes Connect中添加程序测试用户</li>
<li>在设备中登录你的 iTunes Store 帐号</li>
<li>购买测试</li>
</ol>
<p><br class="spacer_" /></p>
<p>我们从编写支持事务所需代码开始。</p>
<p><br class="spacer_" /></p>
<h3>1. 编写代码支持事务</h3>
<p><br class="spacer_" /></p>
<p>首先注意：你将负责开发产品购买的用户界面。StoreKit 未提供任何与用户界面相关的元素。如果你希望你的购买用户界面与App Store一样，那么你要自己完成。</p>
<p><br class="spacer_" /></p>
<p>下面所有代码都是有关事务处理的后台部分。这是一个单独的类只有一条简单的API以供外部类（比如view controller）调用进行购买。如果你找到将其集成到你程序的购买部分的方法，那么我推荐你使用类似方案。</p>
<p><br class="spacer_" /></p>
<p>首先，需要遵循 SKPaymentTransactionObserver 协议:</p>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// InAppPurchaseManager.h</span><br />
<br />
<span style="color: #11740a; font-style: italic;">// add a couple notifications sent out when the transaction completes</span><br />
<span style="color: #6e371a;">#define kInAppPurchaseManagerTransactionFailedNotification @&quot;kInAppPurchaseManagerTransactionFailedNotification&quot;</span><br />
<span style="color: #6e371a;">#define kInAppPurchaseManagerTransactionSucceededNotification @&quot;kInAppPurchaseManagerTransactionSucceededNotification&quot;</span><br />
<br />
…<br />
<br />
<span style="color: #a61390;">@interface</span> InAppPurchaseManager <span style="color: #002200;">:</span> <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/"><span style="color: #400080;">NSObject</span></a> &lt;SKProductsRequestDelegate, SKPaymentTransactionObserver&gt;<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; …<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">// public methods</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>loadStore;<br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>canMakePurchases;<br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>purchaseProUpgrade;<br />
<br />
<span style="color: #a61390;">@end</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>上面我们定义了两个新的notification，它们将作为购买事务的结果被发送。在上例中我们仍然使用与获取产品描述同一个InAppPurchaseManager类。</p>
<p><br class="spacer_" /></p>
<div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #11740a; font-style: italic;">// InAppPurchaseManager.m</span><br />
<br />
<span style="color: #6e371a;">#define kInAppPurchaseProUpgradeProductId @&quot;com.runmonster.runmonsterfree.upgradetopro&quot;</span><br />
<br />
…<br />
<br />
<span style="color: #6e371a;">#pragma -</span><br />
<span style="color: #6e371a;">#pragma Public methods</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// call this method once on startup</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>loadStore<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// restarts any purchases if they were interrupted last time the app was open</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>SKPaymentQueue defaultQueue<span style="color: #002200;">&#93;</span> addTransactionObserver<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// get the product description (defined in early sections)</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self requestProUpgradeProductData<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// call this before making a purchase</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>canMakePurchases<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>SKPaymentQueue canMakePayments<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// kick off the upgrade transaction</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>purchaseProUpgrade<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; SKPayment <span style="color: #002200;">*</span>payment <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>SKPayment paymentWithProductIdentifier<span style="color: #002200;">:</span>kInAppPurchaseProUpgradeProductId<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>SKPaymentQueue defaultQueue<span style="color: #002200;">&#93;</span> addPayment<span style="color: #002200;">:</span>payment<span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #6e371a;">#pragma -</span><br />
<span style="color: #6e371a;">#pragma Purchase helpers</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// saves a record of the transaction by storing the receipt to disk</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>recordTransaction<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKPaymentTransaction <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>transaction<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>transaction.payment.productIdentifier isEqualToString<span style="color: #002200;">:</span>kInAppPurchaseProUpgradeProductId<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// save the transaction receipt to disk</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/"><span style="color: #400080;">NSUserDefaults</span></a> standardUserDefaults<span style="color: #002200;">&#93;</span> setValue<span style="color: #002200;">:</span>transaction.transactionReceipt forKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;proUpgradeTransactionReceipt&quot;</span> <span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/"><span style="color: #400080;">NSUserDefaults</span></a> standardUserDefaults<span style="color: #002200;">&#93;</span> synchronize<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// enable pro features</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>provideContent<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/"><span style="color: #400080;">NSString</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>productId<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>productId isEqualToString<span style="color: #002200;">:</span>kInAppPurchaseProUpgradeProductId<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// enable the pro features</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/"><span style="color: #400080;">NSUserDefaults</span></a> standardUserDefaults<span style="color: #002200;">&#93;</span> setBool<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span> forKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;isProUpgradePurchased&quot;</span> <span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/"><span style="color: #400080;">NSUserDefaults</span></a> standardUserDefaults<span style="color: #002200;">&#93;</span> synchronize<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// removes the transaction from the queue and posts a notification with the transaction result</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>finishTransaction<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKPaymentTransaction <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>transaction wasSuccessful<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>wasSuccessful<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// remove the transaction from the payment queue.</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>SKPaymentQueue defaultQueue<span style="color: #002200;">&#93;</span> finishTransaction<span style="color: #002200;">:</span>transaction<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span style="color: #400080;">NSDictionary</span></a> <span style="color: #002200;">*</span>userInfo <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/"><span style="color: #400080;">NSDictionary</span></a> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>transaction, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;transaction&quot;</span> , <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>wasSuccessful<span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// send out a notification that we’ve finished the transaction</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/"><span style="color: #400080;">NSNotificationCenter</span></a> defaultCenter<span style="color: #002200;">&#93;</span> postNotificationName<span style="color: #002200;">:</span>kInAppPurchaseManagerTransactionSucceededNotification object<span style="color: #002200;">:</span>self userInfo<span style="color: #002200;">:</span>userInfo<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// send out a notification for the failed transaction</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/"><span style="color: #400080;">NSNotificationCenter</span></a> defaultCenter<span style="color: #002200;">&#93;</span> postNotificationName<span style="color: #002200;">:</span>kInAppPurchaseManagerTransactionFailedNotification object<span style="color: #002200;">:</span>self userInfo<span style="color: #002200;">:</span>userInfo<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// called when the transaction was successful</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>completeTransaction<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKPaymentTransaction <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>transaction<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self recordTransaction<span style="color: #002200;">:</span>transaction<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self provideContent<span style="color: #002200;">:</span>transaction.payment.productIdentifier<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self finishTransaction<span style="color: #002200;">:</span>transaction wasSuccessful<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// called when a transaction has been restored and and successfully completed</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>restoreTransaction<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKPaymentTransaction <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>transaction<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self recordTransaction<span style="color: #002200;">:</span>transaction.originalTransaction<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self provideContent<span style="color: #002200;">:</span>transaction.originalTransaction.payment.productIdentifier<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self finishTransaction<span style="color: #002200;">:</span>transaction wasSuccessful<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;<br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// called when a transaction has failed</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>failedTransaction<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKPaymentTransaction <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>transaction<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>transaction.error.code <span style="color: #002200;">!=</span> SKErrorPaymentCancelled<span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// error!</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self finishTransaction<span style="color: #002200;">:</span>transaction wasSuccessful<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">else</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #11740a; font-style: italic;">// this is fine, the user just cancelled, so don’t notify</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>SKPaymentQueue defaultQueue<span style="color: #002200;">&#93;</span> finishTransaction<span style="color: #002200;">:</span>transaction<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<span style="color: #002200;">&#125;</span><br />
<br />
<span style="color: #6e371a;">#pragma mark -</span><br />
<span style="color: #6e371a;">#pragma mark SKPaymentTransactionObserver methods</span><br />
<br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #11740a; font-style: italic;">// called when the transaction status is updated</span><br />
<span style="color: #11740a; font-style: italic;">//</span><br />
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>paymentQueue<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>SKPaymentQueue <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>queue updatedTransactions<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/"><span style="color: #400080;">NSArray</span></a> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>transactions<br />
<span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #a61390;">for</span> <span style="color: #002200;">&#40;</span>SKPaymentTransaction <span style="color: #002200;">*</span>transaction <span style="color: #a61390;">in</span> transactions<span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">switch</span> <span style="color: #002200;">&#40;</span>transaction.transactionState<span style="color: #002200;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">case</span> SKPaymentTransactionStatePurchased<span style="color: #002200;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self completeTransaction<span style="color: #002200;">:</span>transaction<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">case</span> SKPaymentTransactionStateFailed<span style="color: #002200;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self failedTransaction<span style="color: #002200;">:</span>transaction<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">case</span> SKPaymentTransactionStateRestored<span style="color: #002200;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#91;</span>self restoreTransaction<span style="color: #002200;">:</span>transaction<span style="color: #002200;">&#93;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">default</span><span style="color: #002200;">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #a61390;">break</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #002200;">&#125;</span><br />
<span style="color: #002200;">&#125;</span></div></td></tr></tbody></table></div>
<p><br class="spacer_" /></p>
<p>要测试上面的新代码，你还需要编写调用 loadStore, canMakePurchases 以及 purchaseProUpgrade 方法的代码。</p>
<p><br class="spacer_" /></p>
<p>有关上述代码的详细解释，请参考官方 <a href="http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/StoreKitGuide/AddingaStoretoYourApplication/AddingaStoretoYourApplication.html#//apple_ref/doc/uid/TP40008267-CH101-SW1">In  App Purchase Programming Guide （IAP编程指南）</a></p>
<p><br class="spacer_" /></p>
<p>上述代码有几个部分是针对我的程序的。例如，在 provideContent:中，NSUserDefaults 中的@&#8221;isProUpgradePurchased&#8221; BOOL 字段被设定为 YES。程序的其他部分将检查此BOOL值以确定是否需要启动专业版功能。如果你正好也要实现免费升级专业版的功能，那么你可以使用同样的方法。</p>
<p><br class="spacer_" /></p>
<h3>2. 添加测试用户</h3>
<p><br class="spacer_" /></p>
<p>为测试上述代码，你需要在 iTunes Connect 中创建测试用户以对IAP功能进行测试。你可以使用测试帐号购买产品而不被Apple收取费用。</p>
<p>按以下步骤创建测试用户：</p>
<ol>
<li>登录到 <a href="http://developer.apple.com/iphone">http://developer.apple.com/iphone</a></li>
<li>进入 iTunes Connect</li>
<li>选择iTunes Connect首页中的 “Manage Users”</li>
<li>选择 “In App Purchase Test User”</li>
<li>选择 “Add New User”</li>
<li>填入用户信息. 所有信息都不必是合法的。建议使用虚假简短的email地址及简短的密码。</li>
<li>选择 “Save”</li>
</ol>
<p><br class="spacer_" /></p>
<p>测试时你需要输入这些email地址和密码。</p>
<p><br class="spacer_" /></p>
<h3>3. 在你的设备中退出登录</h3>
<p><br class="spacer_" /></p>
<p>在进行程序购买功能测试前，你必须在你的设备中退出iTunes Store。遵循以下步骤：</p>
<ol>
<li>打开Settings App</li>
<li>点击 “Store” 行</li>
<li>点击 “Sign Out”</li>
</ol>
</div>
<div>
<p><br class="spacer_" /></p>
<h3>4. 购买测试</h3>
<p><br class="spacer_" /></p>
<p>现在，终于可以开始进行IAP功能的测试了。测试很简单：</p>
<ol>
<li>运行你设备中的程序</li>
<li>进行购买</li>
<li>当程序提示输入用户名和密码时，输入参数用户的信息</li>
</ol>
<p><br class="spacer_" /></p>
<p>如果你使用同一账户进行购买时，系统将提示你已经购买了此产品。按“Yes”就可以再次下载此产品。</p>
<p><br class="spacer_" /></p>
<h2>总结</h2>
<p><br class="spacer_" /></p>
<p>实现IAP功能比想象的要复杂许多。我可是经过无数痛苦的经历才完成我的程序。希望能够帮助其他开发者减轻他们的痛苦。</p>
<p><br class="spacer_" /></p>
<p>原文见：<a title="In App Purchases: A Full Walkthrough" rel="bookmark" href="http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/">In  App  Purchases: A Full Walkthrough</a></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/iap%ef%bc%88%e7%a8%8b%e5%ba%8f%e5%86%85%e8%b4%ad%e4%b9%b0%ef%bc%89-%e5%ae%8c%e5%85%a8%e6%94%bb%e7%95%a5/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>以密码方式显示UITextField文本</title>
		<link>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bb%a5%e5%af%86%e7%a0%81%e6%96%b9%e5%bc%8f%e6%98%be%e7%a4%bauitextfield%e6%96%87%e6%9c%ac</link>
		<comments>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bb%a5%e5%af%86%e7%a0%81%e6%96%b9%e5%bc%8f%e6%98%be%e7%a4%bauitextfield%e6%96%87%e6%9c%ac#comments</comments>
		<pubDate>Sun, 25 Jul 2010 13:44:14 +0000</pubDate>
		<dc:creator>bagusflyer</dc:creator>
				<category><![CDATA[用户界面]]></category>
		<category><![CDATA[编程]]></category>
		<category><![CDATA[代码片段]]></category>

		<guid isPermaLink="false">http://www.iphone-geek.cn/?p=988</guid>
		<description><![CDATA[很简单，如下：
1textField.secureTextEntry = YES;


]]></description>
			<content:encoded><![CDATA[<p>很简单，如下：</p>
<p><div class="codecolorer-container objc mac-classic" style="overflow:auto;white-space:nowrap;border: 1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="objc codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">textField.secureTextEntry <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;</div></td></tr></tbody></table></div>
</p>
<p><br class="spacer_" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.iphone-geek.cn/%e7%bc%96%e7%a8%8b/%e4%bb%a5%e5%af%86%e7%a0%81%e6%96%b9%e5%bc%8f%e6%98%be%e7%a4%bauitextfield%e6%96%87%e6%9c%ac/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
