<?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>F.A.B.L.E &#187; Cocoa</title>
	<atom:link href="http://sh3ng.com/category/dev/cocoa/feed/" rel="self" type="application/rss+xml" />
	<link>http://sh3ng.com</link>
	<description>What A Long, Strange Trip It&#039;s Been</description>
	<lastBuildDate>Sat, 04 Sep 2010 03:41:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>dSYM wtf</title>
		<link>http://sh3ng.com/2010/04/dsym-wtf/</link>
		<comments>http://sh3ng.com/2010/04/dsym-wtf/#comments</comments>
		<pubDate>Fri, 23 Apr 2010 11:42:12 +0000</pubDate>
		<dc:creator>黑眼圈</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[dSYM]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://sh3ng.com/?p=439</guid>
		<description><![CDATA[在XCODE编译项目之后,会在app旁看见一个同名的dSYM文件. 他是一个编译的中转文件,简单说就是debug的symbols包含在这个文件中. 他有什么作用? 当release的版本 crash的时候,会有一个日志文件,包含出错的内存地址, 使用symbolicatecrash工具能够把日志和dSYM文件转换成可以阅读的log信息,也就是将内存地址,转换成程序里的函数或变量和所属于的文件名. 有一篇详细的blog讲了这个过程 http://www.anoshkin.net/blog/2008/09/09/iphone-crash-logs/ 将类似 Thread 0 Crashed: 0 libobjc.A.dylib 0x300c87ec 0x300bb000 + 55276 1 MobileLines 0&#215;00006434 0&#215;1000 + 21556 2 MobileLines 0x000064c2 0&#215;1000 + 21698 3 UIKit 0x30a740ac 0x30a54000 + 131244 的log信息转换成 Thread 0 Crashed: 0 libobjc.A.dylib 0x300c87ec objc_msgSend + 20 1 MobileLines 0&#215;00006434 -[BoardView setSelectedPiece:] (BoardView.m:321) 2 MobileLines 0x000064c2 [...]]]></description>
			<content:encoded><![CDATA[<p>在XCODE编译项目之后,会在app旁看见一个同名的dSYM文件.<br />
他是一个编译的中转文件,简单说就是debug的symbols包含在这个文件中.</p>
<p>他有什么作用? 当release的版本 crash的时候,会有一个日志文件,包含出错的内存地址, 使用symbolicatecrash工具能够把日志和dSYM文件转换成可以阅读的log信息,也就是将内存地址,转换成程序里的函数或变量和所属于的文件名.<br />
<span id="more-439"></span><br />
有一篇详细的blog讲了这个过程</p>
<p>http://www.anoshkin.net/blog/2008/09/09/iphone-crash-logs/</p>
<p>将类似</p>
<blockquote><p>Thread 0 Crashed:<br />
0   libobjc.A.dylib           0x300c87ec 0x300bb000 + 55276<br />
1   MobileLines               0&#215;00006434 0&#215;1000 + 21556<br />
2   MobileLines               0x000064c2 0&#215;1000 + 21698<br />
3   UIKit                     0x30a740ac 0x30a54000 + 131244
</p></blockquote>
<p>的log信息转换成</p>
<blockquote><p>Thread 0 Crashed:<br />
0   libobjc.A.dylib           0x300c87ec objc_msgSend + 20<br />
1   MobileLines               0&#215;00006434 -[BoardView setSelectedPiece:] (BoardView.m:321)<br />
2   MobileLines               0x000064c2 -[BoardView touchesBegan:withEvent:] (BoardView.m:349)<br />
3   UIKit                     0x30a740ac -[UIWindow sendEvent:] + 264</p></blockquote>
<p>的有用信息.</p>
<p>工具symbolicatecrash隐藏在/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneRemoteDevice.xcodeplugin/Contents/Resources/symbolicatecrash </p>
<p>所以一般复制到/usr/local/bin/ 成为命令行直接调用</p>
<blockquote><p>$ sudo cp /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneRemoteDevice.xcodeplugin/Contents/Resources/symbolicatecrash /usr/local/bin/</p></blockquote>
<p>这个时候运行</p>
<blockquote><p>$ symbolicatecrash -h</p></blockquote>
<p>就能看见帮助信息了.</p>
<p>这个时候,问题又来了..每次编译后的dsym文件都要手动保存一次,很是麻烦.</p>
<p>于是有人写了一个脚本,自动在编译后保存该文件.<br />
请参考:</p>
<p>http://www.cimgf.com/2009/12/23/automatically-save-the-dsym-files/</p>
<p>脚本我复制过来在下面</p>
<blockquote><p>
#!/bin/sh</p>
<p>if [ "$BUILD_STYLE" == "Debug" ]; then<br />
  echo &#8220;Skipping debug&#8221;<br />
  exit 0;<br />
fi</p>
<p>if [ "$EFFECTIVE_PLATFORM_NAME" == "-iphonesimulator" ]; then<br />
  echo &#8220;Skipping simulator build&#8221;<br />
  exit 0;<br />
fi</p>
<p>SRC_PATH=${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}<br />
RELATIVE_DEST_PATH=dSYM/${EXECUTABLE_NAME}.$(date +%Y%m%d%H%M%S).app.dSYM<br />
DEST_PATH=${PROJECT_DIR}/${RELATIVE_DEST_PATH}<br />
echo &#8220;moving ${SRC_PATH} to ${DEST_PATH}&#8221;</p>
<p>mv &#8220;${SRC_PATH}&#8221; &#8220;${DEST_PATH}&#8221;</p>
<p>if [ -f ".git/config" ]; then<br />
  git add &#8220;${RELATIVE_DEST_PATH}&#8221;<br />
  git commit -m &#8220;Added dSYM file for ${BUILD_STYLE} build&#8221; &#8220;${RELATIVE_DEST_PATH}&#8221;<br />
fi
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://sh3ng.com/2010/04/dsym-wtf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为你的应用添加In App Purchase</title>
		<link>http://sh3ng.com/2009/10/practice-in-app-purchase/</link>
		<comments>http://sh3ng.com/2009/10/practice-in-app-purchase/#comments</comments>
		<pubDate>Sun, 18 Oct 2009 21:58:36 +0000</pubDate>
		<dc:creator>黑眼圈</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[app store]]></category>
		<category><![CDATA[in app purchase]]></category>
		<category><![CDATA[itunes]]></category>
		<category><![CDATA[storekit]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://doskoi.cn/?p=300</guid>
		<description><![CDATA[自从10月16日苹果发送给所有开发者的那一封信，通知了程序内购买将可用于免费应用，我认为这也宣告了LITE版的时代结束。 成千上万的免费版的软件或游戏，将作为限制了功能的完整版免费发售，如果用户觉得有意购买，可以直接解锁完整版的功能或购买附加内容。 本文讲阐述如何为你现有的应用或游戏添加程序内购买(In App Purchase)功能。 阅读前提：假设了你拥有一定的iPhone SDK开发基础，和App Store实践经验。 你的程序需要唯一的Bundle ID, 如果已经发布的程序使用了通配符，那么就不能直接添加该功能。如果拥有了唯一的ID，请在program portal中添加你的app id，允许程序使用内购买(Enable In App Purchase)。 在设计好你的程序内购买的功能以后，首先需要定义元数据。来到iTunes Connect，在Manage Your In App Purchases中为你的程序添加一个程序内购买的商品。 上面第一个部分是添加的内部信息。参考名称，ID，类型，和价格。以及各种本地化信息。 这里简单说一下类型的选择，其他信息，以及In App Purchase支持什么类型的商品请查看Getting Started with In App Purchase。 Non-consumable 默认类型，非消耗品，具有持久性，特点是一次性购买，可用在所有设备。例如解锁游戏的储存关卡功能。 Consumable 消耗品，用完或使用后消失，可多次购买，不能用在所有的设备，例如游戏中的血瓶或技能书。 Subscription 订阅，和消耗品一样，除了可以在设备之间共享。 创建购买流程 大致可以分为十个步骤： 验证App Store存取权限 这样做是因为，家长控制或一些公司的配置文件阻止了此功能，使用支付队列的查询功能canMakePayments来确定用户是否有权限购买，返回值YES代表可以购买/NO代表没有权限购买。 载入目录 载入储存在本地或者远程的商品目录。 获得商品本地化信息 程序向App Store发起查询请求获得目录中商品的本地化信息。： myPossibleProds = [NSSet setWithObjects: @”myProd1”, @”myProd2”, @”myProd3, nil]; [...]]]></description>
			<content:encoded><![CDATA[<p>自从10月16日苹果发送给所有开发者的那<a href="https://developer.apple.com/iphone/appstore/inapppurchase.html">一封信</a>，通知了程序内购买将可用于免费应用，我认为这也宣告了LITE版的时代结束。</p>
<p>成千上万的免费版的软件或游戏，将作为限制了功能的完整版免费发售，如果用户觉得有意购买，可以直接解锁完整版的功能或购买附加内容。<br />
本文讲阐述如何为你现有的应用或游戏添加程序内购买(In App Purchase)功能。</p>
<p>阅读前提：假设了你拥有一定的iPhone SDK开发基础，和App Store实践经验。<br />
<span id="more-300"></span><br />
你的程序需要唯一的Bundle ID, 如果已经发布的程序使用了通配符，那么就不能直接添加该功能。如果拥有了唯一的ID，请在program portal中添加你的app id，允许程序使用内购买(Enable In App Purchase)。</p>
<p>在设计好你的程序内购买的功能以后，首先需要定义元数据。来到<a href="https://itunesconnect.apple.com">iTunes Connect</a>，在Manage Your In App Purchases中为你的程序添加一个程序内购买的商品。</p>
<p><a href="http://doskoi.cn/wp-content/uploads/2009/10/add.png"><img class="alignnone size-medium wp-image-310" title="add" src="http://doskoi.cn/wp-content/uploads/2009/10/add-300x254.png" alt="add" width="300" height="254" /></a></p>
<p>上面第一个部分是添加的内部信息。参考名称，ID，类型，和价格。以及各种本地化信息。<br />
这里简单说一下类型的选择，其他信息，以及In App Purchase支持什么类型的商品请查看<a href="http://developer.apple.com/iphone/news/pdf/in_app_purchase.pdf">Getting Started with In App Purchase</a>。</p>
<p>Non-consumable 默认类型，非消耗品，具有持久性，特点是一次性购买，可用在所有设备。例如解锁游戏的储存关卡功能。<br />
Consumable 消耗品，用完或使用后消失，可多次购买，不能用在所有的设备，例如游戏中的血瓶或技能书。<br />
Subscription 订阅，和消耗品一样，除了可以在设备之间共享。</p>
<p><strong>创建购买流程</strong><br />
大致可以分为十个步骤：</p>
<ol>
<li>验证App Store存取权限<br />
这样做是因为，家长控制或一些公司的配置文件阻止了此功能，使用支付队列的查询功能canMakePayments来确定用户是否有权限购买，返回值YES代表可以购买/NO代表没有权限购买。</li>
<li>载入目录<br />
载入储存在本地或者远程的商品目录。</li>
<li>获得商品本地化信息<br />
程序向App Store发起查询请求获得目录中商品的本地化信息。：<br />
<code>myPossibleProds = [NSSet setWithObjects: @”myProd1”, @”myProd2”, @”myProd3, nil];<br />
myProdRequest = [[SKProductsRequest alloc] initWithProductIdentifiers: myPossibleProds];<br />
myProdRequest.delegate = myProductsRequestDelegate;<br />
[myProdRequest start];</code><br />
程序接收来自App Store的回应：<br />
<code>-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response<br />
response包含可能的信息<br />
response.products //产品信息<br />
response.invalidProductIdentifiers //错误的产品标示符</code><br />
错误的产品可能由下面的原因导致：</p>
<ul>
<li>商品未在 iTunes Connect中录入。</li>
<li>商品没有选择“Cleared for Sale”。</li>
<li>商品还没有传播到所有服务器。</li>
</ul>
</li>
<li>创建商品信息<br />
前面的步骤获得了产品信息的数组用以呈现：<br />
<code>myAvailableProductsArray = response.products;<br />
for (SKProduct* aProduct in myAvailableProductsArray) {<br />
diplayTitle  = aProduct.localizedTitle;<br />
displayDesc  = aProduct.localizedDescription;<br />
displayPrice = aProduct.price;<br />
}</code></li>
<li>呈现商品信息<br />
在UI中显示前面获得的信息</li>
<li>请求支付<br />
<code>myPayment = [SKPayment paymentForProductIdentifier: selectedProdID userInfo: nil]; </code><br />
或<br />
<code>myPayment = [SKPayment paymentForProduct: selectedProduct userInfo: nil]; </code><br />
然后提交到队列<br />
<code>defaultPaymentQueue = [SKPaymentQueue defaultQueue];<br />
[defaultPaymentQueue addTransactionObserver: myObserver];<br />
<del datetime="2009-10-18T20:51:30+00:00">[defaultPaymentQueue addPayment: myPayment]; </del><br />
[defaultPaymentQueue addPayment: myRequest];<br />
</code><br />
<code>- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions</code></li>
<p><code> </code></p>
<li>验证支付的事务<br />
<code>for(SKPaymentTransaction *aTransaction in transactions) {<br />
switch (aTransaction.transactionState ) {</code></p>
<p><code> // 商品进入购买流程<br />
case SKPaymentTransactionStatePurchasing:<br />
...<br />
break;<br />
<strong> // 成功购买商品<br />
case SKPaymentTransactionStatePurchased:<br />
...<br />
break;<br />
// 已经购买过该商品<br />
case SKPaymentTransactionStateRestored:<br />
...<br />
break; </strong><br />
// 用户取消交易<br />
case: SKPaymentTransactionStateFailed<br />
...<br />
break; </code><br />
App Store的交易回执<br />
aTransaction.transactionReceipt</p>
<ul>
<li>Used to validate e-commerce transaction</li>
<li>Cryptographically signed chunk of data</li>
<li>Contains information about the purchase</li>
<li>Can validate using Web-based API</li>
</ul>
<p>收到交易回执以后可以传送到你的服务器处理该交易。<br />
你的服务器可以向苹果发送交易验证信息。<br />
苹果的交易验证地址：https://buy.itunes.apple.com/verifyReceipt<br />
验证数据格式：{ receipt-data : &#8230;}<br />
苹果的返回值如果是{ status : 0 } 那么交易是正确，如果返回任何其他值 { status : any_other_value } 交易就是不成立。<br />
你的服务器收到苹果的验证成功信息以后，返回给应用程序类似于解锁功能等消息。</li>
<li>解锁内置物品火提供远程存取地址<br />
需要注意的地方</p>
<ul>
<li>用户可能随时退出程序。</li>
<li>Store Kit 的交易队列是持久化的。</li>
<li>交易是持久化的。</li>
<li>验证存取。</li>
<li>移除交易。</li>
</ul>
<p><code>[[SKPaymentQueue defaultQueue] finishTransaction: transaction];</code></li>
<li>储存购买<br />
需要将非消耗的购买记录在服务器上，以供用户更换设备或删除程序以后重新安装时再次解锁功能。</li>
<li>提供物品恢复<br />
前面的代码中，已经购买过该商品的处理就是直接解锁。<br />
<code>defaultPaymentQueue = [SKPaymentQueue defaultQueue];<br />
[defaultPaymentQueue restoreCompletedTransactions]; </code></li>
</ol>
<p><strong>测试沙盒环境</strong><br />
只供给测试用户，并且设备上才有效，不能使用模拟器测试。<br />
可以为每个国家的商店添加测试帐号。<br />
不能用来测试其他的iTunes Store特性。<br />
需要为每个测试添加唯一的email地址，可以考虑使用+<br />
payam+usa@example.com—测试美国的商品<br />
payam+uk@example.com—测试英国的商品<br />
payam+jp@example.com—测试日本的商品<br />
测试步骤，需要在设备的设置菜单中iTunes Store登出原有帐户。<br />
然后不要在设置菜单中登录测试帐号，而是直接打开需要测试的程序进行测试。<br />
在这之前需要在iTunes Connect的Manage Users菜单中添加In App Purchase测试用户。</p>
<p><strong>财务报表</strong></p>
<ul>
<li>收入和应用程序同样的规则
<ul>
<li>你获得总收入的70%。</li>
<li>支付日程，使用税，报表等全部都一样。</li>
</ul>
</li>
<li>报表
<ul>
<li>一样的报表格式。</li>
<li>贩卖的标示符栏显示物品的产品ID。</li>
<li>所有者标示符栏显示程序的ID。</li>
</ul>
</li>
</ul>
<p>本文部分内容参考自<a href="http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/StoreKitGuide/index.html">In App Purchase Programming Guide</a>和WWDC 2009 Sessions，如需转载请注明出处。</p>
]]></content:encoded>
			<wfw:commentRss>http://sh3ng.com/2009/10/practice-in-app-purchase/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Xcode 3.2 引入代码静态分析</title>
		<link>http://sh3ng.com/2009/09/xcode-with-static-code-analysis-via-clang/</link>
		<comments>http://sh3ng.com/2009/09/xcode-with-static-code-analysis-via-clang/#comments</comments>
		<pubDate>Fri, 11 Sep 2009 23:26:42 +0000</pubDate>
		<dc:creator>黑眼圈</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[clang]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://doskoi.cn/?p=243</guid>
		<description><![CDATA[Xcode 3.2引入了Clang的代码静态分析功能，在项目设置中替换默认编译器即可开启。 唯一的不足就是xcode 3.2只能安装在snow leopard，对于没有升级的开发者来说比较遗憾。 leopard最新的只有3.1.4，支持使用Instruments通过Wifi调试，据说3.2xcode支持wifi调试。(需要OS 3.1)]]></description>
			<content:encoded><![CDATA[<p>Xcode 3.2引入了<a href="http://iPhoneDeveloperTips.com/xcode/static-code-analysis-clang-and-xcode-3-2.html">Clang的代码静态分析功能</a>，在项目设置中替换默认编译器即可开启。<br />
唯一的不足就是xcode 3.2只能安装在snow leopard，对于没有升级的开发者来说比较遗憾。<br />
leopard最新的只有3.1.4，支持使用Instruments通过Wifi调试，据说3.2xcode支持wifi调试。(需要OS 3.1)</p>
]]></content:encoded>
			<wfw:commentRss>http://sh3ng.com/2009/09/xcode-with-static-code-analysis-via-clang/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to select graphics engine on iPhone</title>
		<link>http://sh3ng.com/2009/08/how-to-select-graphics-engine-on-iphone/</link>
		<comments>http://sh3ng.com/2009/08/how-to-select-graphics-engine-on-iphone/#comments</comments>
		<pubDate>Thu, 20 Aug 2009 02:09:01 +0000</pubDate>
		<dc:creator>黑眼圈</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[UI]]></category>

		<guid isPermaLink="false">http://doskoi.cn/?p=215</guid>
		<description><![CDATA[Overview Architecture Usage]]></description>
			<content:encoded><![CDATA[<p>Overview<br />
<a href="http://www.flickr.com/photos/doskoi/3837950485/" title="Flickr 上 Asuroa 的 Image 2"><img src="http://farm3.static.flickr.com/2567/3837950485_d42b983cca.jpg" width="440"  alt="Image 2" /></a></p>
<p>Architecture<br />
<a href="http://www.flickr.com/photos/doskoi/3838740562/" title="Flickr 上 Asuroa 的 Image 1"><img src="http://farm4.static.flickr.com/3547/3838740562_56662fb354.jpg" width="440"  alt="Image 1" /></a></p>
<p>Usage<br />
<a href="http://www.flickr.com/photos/doskoi/3838740062/" title="Flickr 上 Asuroa 的 Image 3"><img src="http://farm4.static.flickr.com/3501/3838740062_68c7eb41a0.jpg" width="440"  alt="Image 3" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://sh3ng.com/2009/08/how-to-select-graphics-engine-on-iphone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What&#8217;s different on iphone device and simulator</title>
		<link>http://sh3ng.com/2009/08/whats-different-on-iphone-device-and-simulator/</link>
		<comments>http://sh3ng.com/2009/08/whats-different-on-iphone-device-and-simulator/#comments</comments>
		<pubDate>Thu, 20 Aug 2009 01:50:17 +0000</pubDate>
		<dc:creator>黑眼圈</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[device]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[simulator]]></category>

		<guid isPermaLink="false">http://doskoi.cn/?p=209</guid>
		<description><![CDATA[Device vs. Simulator Taking advantage of the differences the code for detect #if TARGET_IPHONE_SIMULATOR // Simulator-specific code #else // iPhone-specific code #end]]></description>
			<content:encoded><![CDATA[<p>Device vs. Simulator<br />
Taking advantage of the differences</p>
<p>the code for detect</p>
<p>#if TARGET_IPHONE_SIMULATOR<br />
// Simulator-specific code<br />
#else<br />
// iPhone-specific code<br />
#end</p>
<p><a title="Flickr 上 Asuroa 的 Image 4" href="http://www.flickr.com/photos/doskoi/3838740216/"><img src="http://farm3.static.flickr.com/2604/3838740216_046664a557.jpg" alt="Image 4" width="440" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://sh3ng.com/2009/08/whats-different-on-iphone-device-and-simulator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
