<?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>不可卷也</title>
	<atom:link href="http://www.xiaojiayi.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.xiaojiayi.com</link>
	<description>njuxjy&#039;s &#38;&#38; driftcloudy&#039;s blog</description>
	<lastBuildDate>Thu, 17 May 2012 09:22:57 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>windows phone 7 推送功能的实现</title>
		<link>http://www.xiaojiayi.com/2012/04/06/windows-phone-7-%e6%8e%a8%e9%80%81%e5%8a%9f%e8%83%bd%e7%9a%84%e5%ae%9e%e7%8e%b0/</link>
		<comments>http://www.xiaojiayi.com/2012/04/06/windows-phone-7-%e6%8e%a8%e9%80%81%e5%8a%9f%e8%83%bd%e7%9a%84%e5%ae%9e%e7%8e%b0/#comments</comments>
		<pubDate>Fri, 06 Apr 2012 07:30:46 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[wp7]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=334</guid>
		<description><![CDATA[最近负责了某移动互联网产品wp7平台的推送模块，在这分享一些关于客户端推送的经验。 我们需要实现的是服务端能根据用户id向客户端推送私信、评论、好友请求、以及基于地理位置的一些信息。 wp7与iOS push的不同   搞过symbian的push，也了解过iOS和android的相关内容，wp7的push和iOS的大致类似，也有一些不同，结合我网产品，主要在下面几个方面，也是没搞过wp7 push的我网服务端需要知道的： 1. Push类型不同 wp7有三种类型的push： Toast：程序前后台都能收到，后台时弹出系统toast框，前台时程序自定义处理方式，push数据为xml格式 Raw：push数据为任意格式(json,xml等等)，但程序仅在前台时能收到，不满足我网客户端需求，本文不考虑这种类型 Tile：在客户端桌面的大图标上显示push（图片，文字等），xml格式数据，本期客户端暂时不需要 因此，暂时只需要考虑Toast类型的push。 2. 客户端token与userid之间的对应 wp7在建立push初期，检查客户端是否存在push通道。若不存在，先创建新通道，向微软MPNS（Microsoft Push Notification Service）索取到一个通道URI（这个URI我网push服务要用），并向我网push服务进行注册。若已存在，询问微软MPNS是否需要更新通道URI，同时使用已保存的通道URI向我网push服务进行注册。若MPNS反馈了新的URI，客户端需要向我网push服务更新注册信息。 注册方式有以下几种方案吧： a) 用户登陆以后，将userid, URI, device id一起发给服务端作对应 b) 不管用户登陆与否，先将URI和device id发给服务端，因为用户手动登陆时总会上传device id给服务端，这样也能做好三者的对应 c) 通过某个固定的现有接口将device id和userid上传 3. Push发送的格式 wp7的toast push只支持xml格式的数据，eg: &#60;wp:Notification xmlns:wp=&#8221;WPNotification&#8221;&#62; &#60;wp:Toast&#62; &#60;wp:Text1&#62;push消息标题&#60;/wp:Text1&#62; &#60;wp:Text2&#62;push消息内容&#60;/wp:Text2&#62; &#60;wp:Param&#62;一些参数键值对&#60;/wp:Param&#62; &#60;/wp:Toast&#62; &#60;/wp:Notification&#62; 其中&#60;wp:Param&#62;中的内容可以用来传参数，eg: &#60;wp:Param&#62;?pushType=10&#38;poiId=20&#38;specialId=15&#60;/wp:Param&#62; 其中，&#60;Param&#62; tag中的内容不能超过256个字符 服务端还要设置一些HTTP头和push参数等，可以参考： http://msdn.microsoft.com/en-us/library/hh202945(v=vs.92).aspx http://www.daveamenta.com/2010-11/send-push-notifications-to-windows-phone-7-from-php/ wp7与Symbian push的不同   Symbian上的push不是真正意义上的push，是使用了后台长连接的方式来实现的伪push。 这样做的缺点有： 费电费流量。后台始终保持着socket连接，每隔几分钟发个心跳包。 从用户开机到用户打开程序这段时间内是接收不到push的，因为后台进程压根不会启动 有很小的几率能造成主程序刷不出数据。这种状况出现过两三次，以至于有次发版前只能把push先咔掉。原因可能和接入点有关。 [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left;">最近负责了某移动互联网产品wp7平台的推送模块，在这分享一些关于客户端推送的经验。</p>
<p>我们需要实现的是服务端能根据用户id向客户端推送私信、评论、好友请求、以及基于地理位置的一些信息。</p>
<h2><span style="color: #ff6600;">wp7与iOS push的不同</span></h2>
<h2> </h2>
<p>搞过symbian的push，也了解过iOS和android的相关内容，wp7的push和iOS的大致类似，也有一些不同，结合我网产品，主要在下面几个方面，也是没搞过wp7 push的我网服务端需要知道的：</p>
<p>1. <strong>Push</strong><strong>类型不同</strong></p>
<p>wp7有三种类型的push：<br />
Toast：程序前后台都能收到，后台时弹出系统toast框，前台时程序自定义处理方式，push数据为xml格式<br />
Raw：push数据为任意格式(json,xml等等)，但程序仅在前台时能收到，不满足我网客户端需求，本文不考虑这种类型<br />
Tile：在客户端桌面的大图标上显示push（图片，文字等），xml格式数据，本期客户端暂时不需要<br />
因此，暂时只需要考虑Toast类型的push。</p>
<p>2. <strong>客户端token</strong><strong>与userid</strong><strong>之间的对应</strong></p>
<p>wp7在建立push初期，检查客户端是否存在push通道。若不存在，先创建新通道，向微软MPNS（Microsoft Push Notification Service）索取到一个通道URI（这个URI我网push服务要用），并向我网push服务进行注册。若已存在，询问微软MPNS是否需要更新通道URI，同时使用已保存的通道URI向我网push服务进行注册。若MPNS反馈了新的URI，客户端需要向我网push服务更新注册信息。<br />
注册方式有以下几种方案吧：<br />
a) 用户登陆以后，将userid, URI, device id一起发给服务端作对应<br />
b) 不管用户登陆与否，先将URI和device id发给服务端，因为用户手动登陆时总会上传device id给服务端，这样也能做好三者的对应<br />
c) 通过某个固定的现有接口将device id和userid上传</p>
<p>3. <strong>Push</strong><strong>发送的格式</strong></p>
<p>wp7的toast push只支持xml格式的数据，eg:<br />
&lt;wp:Notification xmlns:wp=&#8221;WPNotification&#8221;&gt;<br />
&lt;wp:Toast&gt;<br />
&lt;wp:Text1&gt;push消息标题&lt;/wp:Text1&gt;<br />
&lt;wp:Text2&gt;push消息内容&lt;/wp:Text2&gt;<br />
&lt;wp:Param&gt;一些参数键值对&lt;/wp:Param&gt;<br />
&lt;/wp:Toast&gt;<br />
&lt;/wp:Notification&gt;<br />
其中&lt;wp:Param&gt;中的内容可以用来传参数，eg:<br />
&lt;wp:Param&gt;?pushType=10&amp;poiId=20&amp;specialId=15&lt;/wp:Param&gt;<br />
其中，&lt;Param&gt; tag中的内容不能超过256个字符<br />
服务端还要设置一些HTTP头和push参数等，可以参考：<br />
<a href="http://msdn.microsoft.com/en-us/library/hh202945(v=vs.92).aspx">http://msdn.microsoft.com/en-us/library/hh202945(v=vs.92).aspx</a><br />
<a href="http://www.daveamenta.com/2010-11/send-push-notifications-to-windows-phone-7-from-php/">http://www.daveamenta.com/2010-11/send-push-notifications-to-windows-phone-7-from-php/</a></p>
<h2><span style="color: #ff6600;">wp7与Symbian push的不同</span></h2>
<h2> </h2>
<p>Symbian上的push不是真正意义上的push，是使用了后台长连接的方式来实现的伪push。<br />
这样做的缺点有：</p>
<ol>
<li>费电费流量。后台始终保持着socket连接，每隔几分钟发个心跳包。</li>
<li>从用户开机到用户打开程序这段时间内是接收不到push的，因为后台进程压根不会启动</li>
<li>有很小的几率能造成主程序刷不出数据。这种状况出现过两三次，以至于有次发版前只能把push先咔掉。原因可能和接入点有关。</li>
<li>实现复杂度高<br />
1） 系统原生不支持push，push提示的UI还得自己做。一个应用得有三个进程：主进程，后台进程，push提示进程<br />
2） 复杂的进程间通讯，主进程&#8212;&gt;后台进程，后台进程&lt;&#8212;&gt;push提示进程，不同的通讯机制（和带UI的程序通讯，以及和Console程序通讯）<br />
3） 额外的数据结构，用队列缓存push，进程间传递的字符串的解析等</li>
</ol>
<div>总而言之，在Symbian上做push的感觉就是——女屌丝非要穿上黑丝齐B小短裙把自己打扮得像女神，虽然能用，但体验不会好。</div>
<h2><span style="color: #ff6600;">wp7 push的服务端</span></h2>
<h2> </h2>
<p>这里以发私信为例，为了能向某用户发私信push，需要保存有user id，wp7手机device id(唯一标示了一部手机)和URI三者的对应关系。通过user id找到该用户最近使用的device id，再通过device id找到与其一一对应的URI，向该URI发送一堆数据，然后由微软发给指定的客户端。</p>
<p>那么，这一堆数据是怎样的？见官方文档。http://msdn.microsoft.com/en-us/library/hh202945(v=vs.92).aspx<br />
有一些需要注意的地方：</p>
<ol>
<li>
<table>
<tbody>
<tr>
<th>Character</th>
<th>XML encoding</th>
</tr>
<tr>
<td>&lt;</td>
<td>&amp;lt;</td>
</tr>
<tr>
<td>&gt;</td>
<td>&amp;gt;</td>
</tr>
<tr>
<td>&amp;</td>
<td>&amp;amp;</td>
</tr>
<tr>
<td>‘</td>
<td>&amp;apos;</td>
</tr>
<tr>
<td>“</td>
<td>&amp;quot;</td>
</tr>
</tbody>
</table>
<p>上面这些特殊字符需要转换</li>
<li>&lt;wp:Param&gt;中的内容不能超过256个字符</li>
<li>对中文需要转换：转成utf-8后再包一层，比如：“我”转成“&amp;#x6211;”</li>
<li>&lt;wp:Text1&gt;和&lt;wp:Text2&gt;，其中Text1和Text2不是用户可以随便修改的，Text1表示push Toast的标题，Text2表示内容。我原以为可以随便修改，把Text1命名为Title，Text2命名为Content，结果客户端怎么也收不到。Text1和Text2至少要存在一个，不然客户端收不到</li>
<li>&lt;wp:Param&gt;中有三种传参数方式：<br />
1）/page1.xaml    点击Toast后跳到客户端的page1.xmal页面<br />
2）/page1.xaml?value1=1234 &amp;amp;value2=9876    点击Toast后跳到客户端的page1.xmal页面，并把value1和value2传给页面<br />
3）?value1=1234 &amp;amp;value2=9876   点击Toast后跳到客户端的默认首页<br />
我网用的第三种，毕竟让服务端写死客户端的跳转页面不灵活且增加沟通成本，不如跳到默认首页，在其中进行统一跳转处理</li>
</ol>
<p>.net服务端比php会简单一些，至少中文处理要简单些。</p>
<h2><span style="color: #ff6600;">wp7 push的客户端</span></h2>
<h2> </h2>
<h4> Step 1. 打开通道</h4>
<p> 首先需要打开HttpNotificationChannel，得到URI，发送push。</p>
<pre class="brush:csharp">        private void RegisterDevice()
        {
            App app = Application.Current as App;
            app.httpChannel = HttpNotificationChannel.Find(App.channelName);

            if (app.httpChannel != null)
            {
                SubscribeToChannelEvents();
                SubscribeToService();
                SET_COOKIE("channelUri", app.httpChannel.ChannelUri.ToString());
            }
            else
            {
                //Create new channel
                app.httpChannel = new HttpNotificationChannel(App.channelName);
                SubscribeToChannelEvents();
                app.httpChannel.Open();
                app.httpChannel.BindToShellToast();
            }
        }</pre>
<p>先尝试寻找是否有已存在的通道。如果有，表示已经拥有了该设备的URI，可以直接向我网的服务器进行注册；如果没有，创建新的通道，设置事件处理函数，尝试打开通道，此时程序会向MPNS索取URI  </p>
<h4>Step 2. 设置事件处理函数</h4>
<pre class="brush:csharp">        private void SubscribeToChannelEvents()
        {
            App app = Application.Current as App;
            //Register to UriUpdated event - occurs when channel successfully opens
            app.httpChannel.ChannelUriUpdated += new EventHandler&lt;NotificationChannelUriEventArgs&gt;(httpChannel_ChannelUriUpdated);

            //Subscribe to Toast Notifications
            app.httpChannel.ShellToastNotificationReceived += new EventHandler&lt;NotificationEventArgs&gt;(httpChannel_ShellToastNotificationReceived);

            //general error handling for push channel
            app.httpChannel.ErrorOccurred += new EventHandler&lt;NotificationChannelErrorEventArgs&gt;(httpChannel_ExceptionOccurred);

        }</pre>
<p> 订阅Toast push这句目的是为了能让程序在前台收到Push时自定义处理，如果值需要后台接收Push，则不需要这句。</p>
<pre class="brush:csharp">        void httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
        {
            App app = Application.Current as App;
            // Optionally save the URI locally here - e.ChannelUri.ToString();
            string newChannelUri = e.ChannelUri.ToString();
            string oldChannelUri = GET_COOKIE("channelUri") as string;
            if (newChannelUri.CompareTo(oldChannelUri)!=0)
            {
                SET_COOKIE("channelUri", e.ChannelUri.ToString());
                Dispatcher.BeginInvoke(() =&gt;
                {
                    SubscribeToService();
                });
            }
        }

        void httpChannel_ExceptionOccurred(object sender, NotificationChannelErrorEventArgs e)
        {
            // Handle notification exceptions here
        }

        void httpChannel_ShellToastNotificationReceived(object sender, NotificationEventArgs e)
        {
            // This runs when a toast notification is received while the app is running
            if (e.Collection != null)
            {
                Dictionary&lt;string, string&gt; collection = (Dictionary&lt;string, string&gt;)e.Collection;
                Dispatcher.BeginInvoke(() =&gt;
                {
                    //MessageBox.Show(collection["wp:Text2"], collection["wp:Text1"], MessageBoxButton.OK);
                });
            }
        }</pre>
<p>httpChannel_ShellToastNotificationReceived函数不在UI线程中，需要访问UI线程的MessageBox的话需要用Dispatcher.BeginInvoke。<br />
httpChannel_ChannelUriUpdated函数在MPNS返回最新URI时被调用，这里优先使用本地缓存的URI，防止重复注册URI（一般不会，只是做保护处理）。<br />
SubscribeToService中只是简单地调用了客户端现存的一个接口，将device id和URI上传到服务端，服务端此时已经能做好device id，userid, URI的对应了。这个接口由于加上了URI，所以会比较长，因此少调为妙。<br />
此时可以telnet db3.notify.live.net 80，post一些数据给微软，顺利的话应该能在客户端接收到push：</p>
<p> <a href="http://www.xiaojiayi.com/wp-content/uploads/2012/04/1.png"><img class="alignnone size-full wp-image-358" title="1" src="http://www.xiaojiayi.com/wp-content/uploads/2012/04/1.png" alt="" width="572" height="304" /></a></p>
<h4>Step 3. 处理push跳转</h4>
<p>不同的push类型需要跳到客户端的不同页面，在默认首页中增加跳转逻辑，需要和各页面负责人进行沟通，就不详述了。</p>
<h2><span style="color: #ff6600;">用后台代理模仿心跳包</span></h2>
<h2> </h2>
<p> 以上的做法能够满足大部分的推送需求，但是对于一些基于地理位置的推送服务，服务端需要知道客户端的实时经纬度（尽可能做到实时），然后根据用户的当前经纬度判断是否触发推送。因此，客户端需要尽可能实时的将userid和经纬度传给服务端。这在symbian使用心跳包建立push的情况下很容易做到，在心跳包上加上相应字段即可，但是wp7对后台程序的限制很严格，之前也考虑过不走微软的mpns网络，用后台长连接的方式做push，这样服务端不需要做改动，但经过一些调研，发现不可行，原因如下：</p>
<div>
<p>wp7的7.0版本不支持后台运行，只能用mpns做push。 <br />
7.1版本会支持Background Agents，但有很多限制（<a href="http://msdn.microsoft.com/en-us/library/hh202944(v=vs.92).aspx">http://msdn.microsoft.com/en-us/library/hh202944(v=vs.92).aspx</a>）：<br />
1.  后台任务有很多API限制<br />
2.  省电模式下后台代理无法运行，也就无法push<br />
3.  一部手机能开的后台代理数有限制，最少可能只有6个，如果超过限制会引起异常<br />
4.  每30分钟运行一次，期间http长连接能否保持是问题<br />
总的来说，wp7为了省电省流量，对开发者自己的后台任务做了很多限制，体验和实现难度来讲也是用原生的push notification更好一些。</p>
<p>push没法用后台代理来实现，但是一些对不需要严格实时（30分钟一次可以接受）的任务，如上报user id和经纬度，可以使用后台代理实现。可参考：<a href="http://msdn.microsoft.com/en-us/library/hh202961(v=vs.92).aspx">http://msdn.microsoft.com/en-us/library/hh202961(v=vs.92).aspx</a></p>
<h4>Step 1. 主程序中开启后台代理</h4>
<pre class="brush:csharp">protected void StartBackAgent()
        {
            // Obtain a reference to the period task, if one exists
            periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;

            // If the task already exists and background agents are enabled for the
            // application, you must remove the task and then add it again to update
            // the schedule
            if (periodicTask != null)
            {
                RemoveAgent(periodicTaskName);
            }

            periodicTask = new PeriodicTask(periodicTaskName);

            // The description is required for periodic agents. This is the string that the user
            // will see in the background services Settings page on the device.
            periodicTask.Description = "This is Our Background Agent";

            // Place the call to Add in a try block in case the user has disabled agents
            try
            {
                ScheduledActionService.Add(periodicTask);

                // If debugging is enabled, use LaunchForTest to launch the agent in one minute.
                ScheduledActionService.LaunchForTest(periodicTaskName, TimeSpan.FromSeconds(5));
            }
            catch (InvalidOperationException exception)
            {
                if (exception.Message.Contains("BNS Error: The action is disabled"))
                {
                    //MessageBox.Show("Background agents for this application have been disabled by the user.");
                }
                if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
                {
                    // No user action required. The system prompts the user when the hard limit of periodic tasks has been reached.
                }
            }
            catch (SchedulerServiceException)
            {
                // No user action required.
            }
        }</pre>
<div>参考了微软给的示例代码，当然也可以关闭代理：</div>
<div>
<pre class="brush:csharp">        protected void EndBackAgent()
        {
            periodicTask = ScheduledActionService.Find(periodicTaskName) as PeriodicTask;
            if (periodicTask != null)
            {
                RemoveAgent(periodicTaskName);
            }
        }</pre>
<div>LaunchForTest是方便调试使用的，加上try catch是为了防止用户设置了关闭后台代理后引发异常。</div>
<div>
<h4>Step 2. 在ScheduledTaskAgent中获取GPS</h4>
<pre class="brush:csharp">       protected override void OnInvoke(ScheduledTask task)
        {
            //TODO: 添加用于在后台执行任务的代码
         taskName = task.Name;
            GetGPS();
        }

        private void GetGPS()
        {
            if (!SystemCore.Instance.position().IsNaN)
            {
                SendGPSByHttpWebRequest();
            }
            else
            {
                gps_timecount = 0;
                gps_timer = new Timer(new TimerCallback(gps_timer_Tick),null,0,1000);
            }
        }

        void gps_timer_Tick(object sender)
        {
            gps_timecount++;
            gps_timer.Dispose();
            gps_timer = null;
            if (!SystemCore.Instance.position().IsNaN)
            {
                SendGPSByHttpWebRequest();
            }
            else if (gps_timecount &lt; 10)
            {
                gps_timer = new Timer(new TimerCallback(gps_timer_Tick), null, 0, 1000);
            }
        }</pre>
<div>增加了限时处理，超过10秒未取到GPS则放弃此次上传。用Timer而未使用DispatcherTimer的原因是，使用后者必须用BeginInvoke的方式在Dispatcher线程中创建，不然会crash，而在Dispatcher线程中用HttpWebRequest发起http请求没有成功，可能是死锁等原因，暂时没走通这条路，就换了Timer，这样能在后台代理线程中发http。</div>
<div>
<h4>Step 3. 使用独立存储+Mutex从主程序获取user id</h4>
<p>wp7中是没有IPC的，或者说不允许用户创建的程序间进行通信，可以使用独立存储或者IsolatedStorageSettings或者LINQ 2 SQL在主程序和后台代理间进行通信，我只用了独立存储，连Mutex也没加，一是主程序写，代理读，二是程序逻辑不太可能造成冲突。官方不推荐使用IsolatedStorageSettings。</p>
<h4>Step 4. 在ScheduledTaskAgent中使用HttpWebRequest</h4>
<p>数据都准备好了(user id+经纬度)，接下来就是发http了。最开始是按照下面链接中的方法，没有发成功，不过还是有些收获。<a href="http://www.cnblogs.com/yanxiaodi/archive/2012/01/18/2325320.html">http://www.cnblogs.com/yanxiaodi/archive/2012/01/18/2325320.html</a>  然后在网上搜了一圈都试过，没有能成功的。最后找到了一个老外的分享，twitter客户端的push机制，用了里面的一个库，成功了。<a href="http://blogs.msdn.com/b/ptorr/archive/2011/07/12/background-agents-part-2-of-3.aspx">http://blogs.msdn.com/b/ptorr/archive/2011/07/12/background-agents-part-2-of-3.aspx</a> <br />
在http成功发送后得调用NotifyComplete通知操作系统这次任务圆满完成，期待下次继续，不调用的话下次时间片到了不会启动后台代理。在网络请求很长时间不返回的情况下，如果这时间超过了系统能允许后台代理一次运行的时间（25秒），那么就不会调用到NotifyComplete，导致下次无法启动，因此这里有必要加上限时处理。</p>
</div>
</div>
</div>
</div>
<h2><span style="color: #ff6600;">push的统计</span></h2>
<h2> </h2>
<div>
<div>在Symbian上曾做过push统计的事情，push功能推出去需要知道用户的反馈：收到过多少push，分别是什么类型的，用户打开过多少次push，每次分别是什么类型的等等。最方便的做法就是讲统计数据加到心跳包末尾：<br />
在心跳包URL末尾加a=**来统计push。<br />
a=0            默认情况<br />
a=1            客户端在前台时候收到push<br />
a=2            客户端在后台时候收到push<br />
a=3            用户确定<br />
a=4            用户取消<br />
当a=1,2,3,4时，为了统计push类型，在数字后直接跟push类型（0,1,2,…15,16等），不足两位补足两位。如a=101, a=313,a=416等<br />
ps：<br />
Symbian V5用a=**<br />
Symbian V3用b=**<br />
iOS用c=**<br />
安卓目前没有需求，若有就用d=**<br />
iOS由于使用了长连接+APNS结合的两种push方式，所以也能够用这种方法统计一部分数据。<br />
wp7目前没有统计需求，有的话再调研下。</div>
<div> </div>
</div>
<div>最后感谢msdn，google和Stackoverflow。<br />
还不小心发现一枚山寨版Stackoverflow(栈溢出)，叫Segmentfault(段错误) 。</div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2012/04/06/windows-phone-7-%e6%8e%a8%e9%80%81%e5%8a%9f%e8%83%bd%e7%9a%84%e5%ae%9e%e7%8e%b0/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>最近</title>
		<link>http://www.xiaojiayi.com/2012/03/04/%e6%9c%80%e8%bf%91/</link>
		<comments>http://www.xiaojiayi.com/2012/03/04/%e6%9c%80%e8%bf%91/#comments</comments>
		<pubDate>Sat, 03 Mar 2012 17:28:06 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[生活]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=298</guid>
		<description><![CDATA[单位最近抛弃了symbian，结束了我和它这段短暂而意外的缘分。因为业务的需要而转投wp7新项目的开发，项目未启动，技术储备中。出于兴趣之前开始自学iOS，由于和白天wp7的冲突，故放到晚上抽空学习下。 工作后greader使用频率大幅减少，最近一个月就没用过，也许是心态比较浮躁吧，把大把时间都花在微博上了，时间被拆分的支离破碎。 工作大半年内集齐了除iPhone外的几乎apple全系列产品，当然不全是自己买的。有时候开着Carbide敲着symbian代码，想起自己的果粉身份，觉得真是好笑。 wp7的学习打算用和iOS学习不同的方法，相比iOS的“学院派”，打算用“野兽派”，试试哪个效果好。 跟甲鱼说好下次他去北京出差时，我有空的话跟着去蹭吃蹭喝两个礼拜，坐穿北京的地铁。 给LP打了个赌，尽早实现。 自律。]]></description>
			<content:encoded><![CDATA[<p>单位最近抛弃了symbian，结束了我和它这段短暂而意外的缘分。因为业务的需要而转投wp7新项目的开发，项目未启动，技术储备中。出于兴趣之前开始自学iOS，由于和白天wp7的冲突，故放到晚上抽空学习下。</p>
<p>工作后greader使用频率大幅减少，最近一个月就没用过，也许是心态比较浮躁吧，把大把时间都花在微博上了，时间被拆分的支离破碎。</p>
<p>工作大半年内集齐了除iPhone外的几乎apple全系列产品，当然不全是自己买的。有时候开着Carbide敲着symbian代码，想起自己的果粉身份，觉得真是好笑。</p>
<p>wp7的学习打算用和iOS学习不同的方法，相比iOS的“学院派”，打算用“野兽派”，试试哪个效果好。</p>
<p>跟甲鱼说好下次他去北京出差时，我有空的话跟着去蹭吃蹭喝两个礼拜，坐穿北京的地铁。</p>
<p>给LP打了个赌，尽早实现。</p>
<p>自律。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2012/03/04/%e6%9c%80%e8%bf%91/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IOS学习路线</title>
		<link>http://www.xiaojiayi.com/2012/03/04/10000%e5%b0%8f%e6%97%b6ios%e5%ad%a6%e4%b9%a0%ef%bc%881%ef%bc%89%e5%ad%a6%e4%b9%a0%e8%b7%af%e7%ba%bf/</link>
		<comments>http://www.xiaojiayi.com/2012/03/04/10000%e5%b0%8f%e6%97%b6ios%e5%ad%a6%e4%b9%a0%ef%bc%881%ef%bc%89%e5%ad%a6%e4%b9%a0%e8%b7%af%e7%ba%bf/#comments</comments>
		<pubDate>Sat, 03 Mar 2012 16:20:40 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[IOS]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=289</guid>
		<description><![CDATA[先按照cocoachina给新手整理的学习路线过一遍。http://www.cocoachina.com/special/fornew.html 看完《iphone developer cookbook》，Stanford CS 193P 2011~2012 做个ipad图片滤镜小程序 看资料，敲代码，循环往复 一些点： 收藏的一些url github QK iOS src]]></description>
			<content:encoded><![CDATA[<ol>
<li>先按照cocoachina给新手整理的学习路线过一遍。http://www.cocoachina.com/special/fornew.html</li>
<li>看完《iphone developer cookbook》，Stanford CS 193P 2011~2012</li>
<li>做个ipad图片滤镜小程序</li>
<li>看资料，敲代码，循环往复</li>
</ol>
<p>一些点：</p>
<ul>
<li>收藏的一些url</li>
<li>github</li>
<li>QK iOS src</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2012/03/04/10000%e5%b0%8f%e6%97%b6ios%e5%ad%a6%e4%b9%a0%ef%bc%881%ef%bc%89%e5%ad%a6%e4%b9%a0%e8%b7%af%e7%ba%bf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>图像滤镜之程序实现</title>
		<link>http://www.xiaojiayi.com/2011/11/13/%e5%9b%be%e5%83%8f%e6%bb%a4%e9%95%9c%e4%b9%8b%e7%a8%8b%e5%ba%8f%e5%ae%9e%e7%8e%b0/</link>
		<comments>http://www.xiaojiayi.com/2011/11/13/%e5%9b%be%e5%83%8f%e6%bb%a4%e9%95%9c%e4%b9%8b%e7%a8%8b%e5%ba%8f%e5%ae%9e%e7%8e%b0/#comments</comments>
		<pubDate>Sun, 13 Nov 2011 15:43:28 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[symbian]]></category>
		<category><![CDATA[图像处理]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=245</guid>
		<description><![CDATA[前段时间做了一段时间塞班平台的图像处理研究，想要做出类似于instagram、Q拍那样的滤镜特效，在手机拍完照后可以用我们提供的滤镜对照片进行美化处理（有空再做个ios版的）。看了一些instagram、Q拍、美图秀秀、可牛快拍等软件做出来的效果，对于图像处理零基础的我表示鸭梨很大。从RGB通道、alpha通道、位图结构、灰度图、图层、颜色表等概念看起，然后了解基本的图像处理方法如锐化、柔化、扩散、雕刻、黑白、反色等基本特效的原理，到高斯模糊、图像混合、柏林噪声等进阶的玩法，到最后总结出了一套做图像特效的方法，给我一个.psd的photoshop源文件，我便可以根据里面的拆分步骤用程序去实现该效果。其中参考了不少国外站点的东西，尤其是StackOverflow上找到了很多有用的东东，东拼西凑组成了我图像处理这块的一些心得。先上图吧。 原图如下： &#160; a. 基础效果 这里说基础是因为这些效果不涉及图像混合等更加复杂的东东，只是对每个像素的RGB通道做一些处理。 有的算法一行代码就能解决了，有的稍微复杂些，不过基本国内的网上都能找得到。 黑白 浮雕 素描 lomo 马赛克 扫描线 波普 鱼眼 b. 进阶效果 这里仅作了图像混合，并没有用函数去处理每个RGB分量，毕竟不是专门搞ps的，不知道怎么弄算好看.. 不过貌似可牛快拍里有些效果就是做了图像混合，然后稍做了些处理。这种做法比较没技术含量.. 不适合单独作为产品级的效果，可以作为复杂特效的某些步骤。 早晨 星光 这里就放出两张图了，因为做法其实都一样，最多传的参数不同罢了。当然图像混合也是有学问的，可以参考国外一哥们的系列文章：http://jswidget.com/blog/2011/03/11/image-blending-algorithmpart-i/ c.高级特效 下面两个效果挺花时间的，主要要知道怎么做比较费时间，做的过程的话第二个效果也比较复杂，是根据.psd文件的拆分步骤一步步做出来的，所以在移动平台上跑有些慢&#8230; 老照片 Nostalgia 做的方法受这个老外的影响很大：http://taptaptap.com/blog/creating-a-camera-plus-fx/ 这是个开发ios上滤镜app的老外设计师写的，而且是夫妻档，貌似老婆是设计师，她将做好的photoshop效果图给源文件给老公，然后老公根据.psd文件做成ios应用放到app store里去卖。我的Nostalgia特效就是模仿的他们的效果。不过老外没有把源代码放上来，就截了段核心函数，然后我自己摸索了好多天，不断的尝试，最后才搞成的效果。里面还涉及到了用Matlab模拟出曲线的函数，竟然用到了四次函数。。不过整个过程还是很享受的，很有乐趣。如果组内有需求，可以帮着搞一下。]]></description>
			<content:encoded><![CDATA[<p>前段时间做了一段时间塞班平台的图像处理研究，想要做出类似于instagram、Q拍那样的滤镜特效，在手机拍完照后可以用我们提供的滤镜对照片进行美化处理（有空再做个ios版的）。看了一些instagram、Q拍、美图秀秀、可牛快拍等软件做出来的效果，对于图像处理零基础的我表示鸭梨很大。从RGB通道、alpha通道、位图结构、灰度图、图层、颜色表等概念看起，然后了解基本的图像处理方法如锐化、柔化、扩散、雕刻、黑白、反色等基本特效的原理，到高斯模糊、图像混合、柏林噪声等进阶的玩法，到最后总结出了一套做图像特效的方法，给我一个.psd的photoshop源文件，我便可以根据里面的拆分步骤用程序去实现该效果。其中参考了不少国外站点的东西，尤其是StackOverflow上找到了很多有用的东东，东拼西凑组成了我图像处理这块的一些心得。先上图吧。</p>
<p>原图如下：</p>
<p><a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/Nostalgia1.bmp"><img class="alignnone size-full wp-image-257" title="Nostalgia" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/Nostalgia1.bmp" alt="" /></a></p>
<p>&nbsp;</p>
<p>a. 基础效果</p>
<p>这里说基础是因为这些效果不涉及图像混合等更加复杂的东东，只是对每个像素的RGB通道做一些处理。 有的算法一行代码就能解决了，有的稍微复杂些，不过基本国内的网上都能找得到。</p>
<ol>
<li>黑白<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/blackwhite.png"><img class="alignnone size-full wp-image-247" title="blackwhite" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/blackwhite.png" alt="" width="600" height="449" /></a></li>
<li>浮雕<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/emboss.png"><img class="alignnone size-full wp-image-248" title="emboss" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/emboss.png" alt="" width="600" height="449" /></a></li>
<li>素描<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/sumiao.png"><img class="alignnone size-full wp-image-255" title="sumiao" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/sumiao.png" alt="" width="600" height="449" /></a></li>
<li>lomo<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/lomo.png"><img class="alignnone size-full wp-image-249" title="lomo" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/lomo.png" alt="" width="600" height="449" /></a></li>
<li>马赛克<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/mosaic.png"><img class="alignnone size-full wp-image-251" title="mosaic" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/mosaic.png" alt="" width="600" height="449" /></a></li>
<li>扫描线<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/scanline.png"><img class="alignnone size-full wp-image-254" title="scanline" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/scanline.png" alt="" width="600" height="449" /></a></li>
<li>波普<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/bopo.png"><img class="alignnone size-full wp-image-258" title="bopo" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/bopo.png" alt="" width="600" height="449" /></a></li>
<li>鱼眼<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/fisheye.png"><img class="alignnone size-full wp-image-259" title="fisheye" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/fisheye.png" alt="" width="600" height="449" /></a></li>
</ol>
<div>b. 进阶效果</div>
<div>这里仅作了图像混合，并没有用函数去处理每个RGB分量，毕竟不是专门搞ps的，不知道怎么弄算好看.. 不过貌似可牛快拍里有些效果就是做了图像混合，然后稍做了些处理。这种做法比较没技术含量.. 不适合单独作为产品级的效果，可以作为复杂特效的某些步骤。</div>
<div>
<ol>
<li>早晨<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/morning.png"><img class="alignnone size-full wp-image-250" title="morning" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/morning.png" alt="" width="600" height="449" /></a></li>
<li>星光<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/star.png"><img class="alignnone size-full wp-image-260" title="star" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/star.png" alt="" width="600" height="449" /></a></li>
</ol>
</div>
<div>这里就放出两张图了，因为做法其实都一样，最多传的参数不同罢了。当然图像混合也是有学问的，可以参考国外一哥们的系列文章：http://jswidget.com/blog/2011/03/11/image-blending-algorithmpart-i/</div>
<div>c.高级特效</div>
<div>下面两个效果挺花时间的，主要要知道怎么做比较费时间，做的过程的话第二个效果也比较复杂，是根据.psd文件的拆分步骤一步步做出来的，所以在移动平台上跑有些慢&#8230;</div>
<div>
<ol>
<li>老照片<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/old-photo.png"><img class="alignnone size-full wp-image-253" title="old photo" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/old-photo.png" alt="" width="600" height="449" /></a></li>
<li>Nostalgia<br />
<a href="http://www.xiaojiayi.com/wp-content/uploads/2011/11/nostalgia.png"><img class="alignnone size-full wp-image-252" title="nostalgia" src="http://www.xiaojiayi.com/wp-content/uploads/2011/11/nostalgia.png" alt="" width="600" height="449" /></a></li>
</ol>
<div>做的方法受这个老外的影响很大：http://taptaptap.com/blog/creating-a-camera-plus-fx/</div>
<div>这是个开发ios上滤镜app的老外设计师写的，而且是夫妻档，貌似老婆是设计师，她将做好的photoshop效果图给源文件给老公，然后老公根据.psd文件做成ios应用放到app store里去卖。我的Nostalgia特效就是模仿的他们的效果。不过老外没有把源代码放上来，就截了段核心函数，然后我自己摸索了好多天，不断的尝试，最后才搞成的效果。里面还涉及到了用Matlab模拟出曲线的函数，竟然用到了四次函数。。不过整个过程还是很享受的，很有乐趣。如果组内有需求，可以帮着搞一下。</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2011/11/13/%e5%9b%be%e5%83%8f%e6%bb%a4%e9%95%9c%e4%b9%8b%e7%a8%8b%e5%ba%8f%e5%ae%9e%e7%8e%b0/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>移植zlib到Symbian实现gzip内存流解压</title>
		<link>http://www.xiaojiayi.com/2011/08/17/%e7%a7%bb%e6%a4%8dzlib%e5%88%b0symbian%e5%ae%9e%e7%8e%b0gzip%e5%86%85%e5%ad%98%e6%b5%81%e8%a7%a3%e5%8e%8b/</link>
		<comments>http://www.xiaojiayi.com/2011/08/17/%e7%a7%bb%e6%a4%8dzlib%e5%88%b0symbian%e5%ae%9e%e7%8e%b0gzip%e5%86%85%e5%ad%98%e6%b5%81%e8%a7%a3%e5%8e%8b/#comments</comments>
		<pubDate>Wed, 17 Aug 2011 14:11:00 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[symbian]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=193</guid>
		<description><![CDATA[客户端（v3版本）原先在处理服务器端传回gzip数据时采用的策略是先将gzip流保存成.gz文件，再用解压文件的方式将数据解压出来。这种方式显然不如直接从内存中实现gzip解压来得高效，但由于Symbian SDK中zlib的版本过低（1.1.3）等原因，网上介绍的很多内存流解压方法并不适用于此： http://apps.hi.baidu.com/share/detail/8355062 http://blog.sina.com.cn/s/blog_4d6f62190100md6k.html http://blog.sina.com.cn/s/blog_65db99840100kwh9.html http://www.devdiv.com/thread-8625-1-1.html http://www.developer.nokia.com/Community/Discussion/showthread.php?155614-GZip-and-RReadStream-problem 在解决过程中遇到了一些困难，开始使用http://apps.hi.baidu.com/share/detail/8355062 中的方法，并且将服务器返回的gzip数据去掉开头的10个gzip header，但程序始终卡在第13行： CBufFlat* CETNetOperator::DeCompressMemL(const TDesC8&#38; aData)         {         TInt nBufferSize = 128;         HBufC8* nSrc = NULL;         HBufC8* nTemp = aData.Mid(10).Alloc();   //去掉开头10个字节         nSrc = nTemp;         CleanupStack::PushL(nSrc);         CBufFlat* nBufFlat = CBufFlat::NewL(nBufferSize);         CleanupStack::PushL(nBufFlat);         CBufferManager* nBufferManager = CBufferManager::NewLC(*nSrc, *nBufFlat,                     nBufferSize);         CEZDecompressor* decompressor = CEZDecompressor::NewLC(*nBufferManager);         while (decompressor-&#62;InflateL())               {// loop here until the file is compressed               }         //    nBufFlat-&#62;Ptr(0);         CleanupStack::PopAndDestroy(3);         return nBufFlat;         }    然后尝试使用Symbian SDK自带的zlib库，include &#60;ezlib.h&#62;，代码如下： int ungzip(char* source, int len, char* des)        {        int ret, have; [...]]]></description>
			<content:encoded><![CDATA[<p>客户端（v3版本）原先在处理服务器端传回gzip数据时采用的策略是先将gzip流保存成.gz文件，再用解压文件的方式将数据解压出来。这种方式显然不如直接从内存中实现gzip解压来得高效，但由于Symbian SDK中zlib的版本过低（1.1.3）等原因，网上介绍的很多内存流解压方法并不适用于此：</p>
<ul>
<li><a href="http://apps.hi.baidu.com/share/detail/8355062">http://apps.hi.baidu.com/share/detail/8355062</a></li>
<li><a href="http://blog.sina.com.cn/s/blog_4d6f62190100md6k.html">http://blog.sina.com.cn/s/blog_4d6f62190100md6k.html</a></li>
<li><a href="http://blog.sina.com.cn/s/blog_65db99840100kwh9.html">http://blog.sina.com.cn/s/blog_65db99840100kwh9.html</a></li>
<li><a href="http://www.devdiv.com/thread-8625-1-1.html">http://www.devdiv.com/thread-8625-1-1.html</a></li>
<li><a href="http://www.developer.nokia.com/Community/Discussion/showthread.php?155614-GZip-and-RReadStream-problem">http://www.developer.nokia.com/Community/Discussion/showthread.php?155614-GZip-and-RReadStream-problem</a></li>
</ul>
<div>在解决过程中遇到了一些困难，开始使用<a href="http://apps.hi.baidu.com/share/detail/8355062">http://apps.hi.baidu.com/share/detail/8355062</a> 中的方法，并且将服务器返回的gzip数据去掉开头的10个gzip header，但程序始终卡在第13行：</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CBufFlat* CETNetOperator::DeCompressMemL(</span><span class="keyword">const</span><span> TDesC8&amp; aData)   </span></span></li>
<li><span>     {   </span></li>
<li class="alt"><span>     TInt nBufferSize = 128;   </span></li>
<li><span>     HBufC8* nSrc = NULL;   </span></li>
<li class="alt"><span>     HBufC8* nTemp = aData.Mid(10).Alloc();   </span><span class="comment">//去掉开头10个字节 </span><span>  </span></li>
<li><span>     nSrc = nTemp;   </span></li>
<li class="alt"><span>     CleanupStack::PushL(nSrc);   </span></li>
<li><span>     CBufFlat* nBufFlat = CBufFlat::NewL(nBufferSize);   </span></li>
<li class="alt"><span>     CleanupStack::PushL(nBufFlat);   </span></li>
<li><span>     CBufferManager* nBufferManager = CBufferManager::NewLC(*nSrc, *nBufFlat,   </span></li>
<li class="alt"><span>                 nBufferSize);   </span></li>
<li><span>     CEZDecompressor* decompressor = CEZDecompressor::NewLC(*nBufferManager);   </span></li>
<li class="alt"><span>     </span><span class="keyword">while</span><span> (decompressor-&gt;InflateL())   </span></li>
<li><span>           {</span><span class="comment">// loop here until the file is compressed </span><span>  </span></li>
<li class="alt"><span>           }   </span></li>
<li><span>     </span><span class="comment">//    nBufFlat-&gt;Ptr(0); </span><span>  </span></li>
<li class="alt"><span>     CleanupStack::PopAndDestroy(3);   </span></li>
<li><span>     </span><span class="keyword">return</span><span> nBufFlat;   </span></li>
<li class="alt"><span>     }   </span></li>
</ol>
</div>
<p>然后尝试使用Symbian SDK自带的zlib库，include &lt;ezlib.h&gt;，代码如下：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="datatypes">int</span><span> ungzip(</span><span class="datatypes">char</span><span>* source, </span><span class="datatypes">int</span><span> len, </span><span class="datatypes">char</span><span>* des)   </span></span></li>
<li><span>    {   </span></li>
<li class="alt"><span>    </span><span class="datatypes">int</span><span> ret, have;   </span></li>
<li><span>    </span><span class="datatypes">int</span><span> offset = 0;   </span></li>
<li class="alt"><span>    z_stream d_stream;   </span></li>
<li><span>    Byte compr[KETNET_BUFFER_SIZE] ={0}, uncompr[KETNET_BUFFER_SIZE * 4] ={0};   </span></li>
<li class="alt"><span>    memcpy(compr, (Byte*) source, len);   </span></li>
<li><span>    uLong comprLen, uncomprLen;   </span></li>
<li class="alt"><span>    comprLen = len;   </span></li>
<li><span>    uncomprLen = KETNET_BUFFER_SIZE * 4;   </span></li>
<li class="alt"><span>    strcpy((</span><span class="datatypes">char</span><span>*) uncompr, </span><span class="string">&#8220;garbage&#8221;</span><span>);   </span></li>
<li><span>    d_stream.zalloc = Z_NULL;   </span></li>
<li class="alt"><span>    d_stream.zfree = Z_NULL;   </span></li>
<li><span>    d_stream.opaque = Z_NULL;   </span></li>
<li class="alt"><span>    d_stream.next_in = compr;   </span></li>
<li><span>    d_stream.avail_in = comprLen;   </span></li>
<li class="alt"><span>    ret = inflateInit2(&amp;d_stream,47);   </span></li>
<li><span>    </span><span class="keyword">if</span><span> (ret != Z_OK)   </span></li>
<li class="alt"><span>        {   </span></li>
<li><span>        </span><span class="keyword">return</span><span> ret;   </span></li>
<li class="alt"><span>        }   </span></li>
<li><span>    </span><span class="keyword">do</span><span>  </span></li>
<li class="alt"><span>        {   </span></li>
<li><span>        d_stream.next_out = uncompr;   </span></li>
<li class="alt"><span>        d_stream.avail_out = uncomprLen;   </span></li>
<li><span>        ret = inflate(&amp;d_stream, Z_NO_FLUSH);   </span></li>
<li class="alt"><span>        </span><span class="keyword">switch</span><span> (ret)   </span></li>
<li><span>            {   </span></li>
<li class="alt"><span>            </span><span class="keyword">case</span><span> Z_NEED_DICT:   </span></li>
<li><span>                ret = Z_DATA_ERROR;   </span></li>
<li class="alt"><span>            </span><span class="keyword">case</span><span> Z_DATA_ERROR:   </span></li>
<li><span>            </span><span class="keyword">case</span><span> Z_MEM_ERROR:   </span></li>
<li class="alt"><span>                (</span><span class="keyword">void</span><span>) inflateEnd(&amp;d_stream);   </span></li>
<li><span>                </span><span class="keyword">return</span><span> ret;   </span></li>
<li class="alt"><span>            }   </span></li>
<li><span>        have = uncomprLen - d_stream.avail_out;   </span></li>
<li class="alt"><span>        memcpy(des + offset, uncompr, have);   </span></li>
<li><span>        offset += have;   </span></li>
<li class="alt"><span>        }   </span></li>
<li><span>    </span><span class="keyword">while</span><span> (d_stream.avail_out == 0);   </span></li>
<li class="alt"><span>    inflateEnd(&amp;d_stream);   </span></li>
<li><span>    memcpy(des + offset, </span><span class="string">&#8220;\0&#8243;</span><span>, 1);   </span></li>
<li class="alt"><span>    </span><span class="keyword">return</span><span> ret;   </span></li>
<li><span>    }  </span></li>
</ol>
</div>
<p>发现程序始终在第17行返回-2，即流初始化Z_STREAM_ERROR错误，zlib1.1.3的zlib.h中说原因是参数设置不正确，stream为空或者windowBits为负。而inflateInit2（）要求windowBits在8~15之间，在其他范围内的值会造成初始化错误。随后改成了15，但是在第26行inflate进行解压时返回值为-3，即Z_DATA_ERROR错误，原因是&#8221;the input data is corrupted (input stream not conforming to the zlib format or incorrect adler32 checksum)&#8221;。</p>
<p>于是怀疑是Symbian自带的zlib的版本问题，刚哥说得自己移植zlib库进去。由于没移植过程序，一开始犯了个错误，原地绕了个圈子：我从网上下了个人家已经编译好的1.2.3版本的zlib.lib文件和几个头文件放到项目工程中去，以为光更换了zlib版本就行了，结果还是那两个错误。最后才走移植的路子，并编译运行成功，现将步骤记录如下：</p>
<p>从网上下载1.2.3的源代码，将下面这些.h .c文件放入工程下面（全部放进去会使工程太大，由于只需要用zlib的解压功能，所以删除了部分没用的文件和函数，还可以继续减减肥，这个以后再做吧）：</p>
<p><a href="http://www.xiaojiayi.com/wp-content/uploads/2011/08/2.jpg"><img title="2" src="http://www.xiaojiayi.com/wp-content/uploads/2011/08/2.jpg" alt="" width="141" height="291" /></a></p>
<p>使用zlib提供的uncompress函数进行解压缩：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>ZEXTERN </span><span class="datatypes">int</span><span> ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, </span><span class="keyword">const</span><span> Bytef *source, uLong sourceLen));  </span></span></li>
</ol>
<div>这个函数的实现其实就是上面的ungzip函数。在inflateInit2（）的时候使用了47，在1.2.3版本的zlib.h中有这么一段话，是1.1.3版本中没有的：</div>
<div><a href="http://www.xiaojiayi.com/wp-content/uploads/2011/08/21.jpg"><img class="alignnone size-full wp-image-196" title="2" src="http://www.xiaojiayi.com/wp-content/uploads/2011/08/21.jpg" alt="" width="642" height="318" /></a></div>
</div>
<p>难怪1.1.3版本的不行，因为在1.1.3版本中的inflateInit2()中对gzip只字未提，只有gzopen()等函数能对.gz的文件进行解压。因此1.1.3版本不支持内存流的gzip解压。</p>
<p>这样以后，一般的项目就算是可以大功告成了。下面的步骤仅针对于自己参与的这个项目，没兴趣的可以跳过：） 由于它在其他地方用到了Symbian SDK自带的系统文件ezlib.h，而这一部分代码没法更改为使用新移植进去的zlib库，所以只能在系统中保持两个库的并存，这样就会造成很多函数名和类、结构体声明重复，无法通过编译。唯一想到的办法就是将新加入的zlib源文件中与老版本的zlib冲突的部分全部重命名，但这是一个巨大的工作量，因为宏定义特别多。那就先给zlib减减肥吧，仅保留需要的解压缩的那部分。过程就不详说了，总之多尝试吧，也不是个容易的活。</p>
<p>在这过程中产生了些副产品：</p>
<ol>
<li>Carbide的断点调试，比打日志好多了，f6单步, f8执行</li>
<li>明白了移植是怎么回事</li>
<li>最好服务端过来的数据头部有gzip数据包的大小信息，<wbr>可以减少客户端动态分配的内存</wbr></li>
</ol>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2011/08/17/%e7%a7%bb%e6%a4%8dzlib%e5%88%b0symbian%e5%ae%9e%e7%8e%b0gzip%e5%86%85%e5%ad%98%e6%b5%81%e8%a7%a3%e5%8e%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>工作一月小记</title>
		<link>http://www.xiaojiayi.com/2011/08/07/%e5%b7%a5%e4%bd%9c%e4%b8%80%e6%9c%88%e5%b0%8f%e8%ae%b0/</link>
		<comments>http://www.xiaojiayi.com/2011/08/07/%e5%b7%a5%e4%bd%9c%e4%b8%80%e6%9c%88%e5%b0%8f%e8%ae%b0/#comments</comments>
		<pubDate>Sun, 07 Aug 2011 09:10:45 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[总结&计划]]></category>
		<category><![CDATA[生活]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=175</guid>
		<description><![CDATA[从入职到现在差不多一个月的时间。只不过是在大半年的张江男生活上又增添了一个月而已，没有什么新奇的地方。由于有过另外两家公司的实习经历，所以难免在工作中会进行些比对。不再是打酱油的实习生，而是需要产出的劳动者，辛苦是自然的，能学到东西是唯一的期许，薪资福利等等不在重点考虑范围。互联网行业，不慎落入LBS的从业人员。业务上的事情需要关注，但不需过多掺杂，有没有钱途不是我说了算，当然愿景是美好的。作为一名入司不久的新人，挨好你的踢才是根本，其他神马都是浮云。 跟两同学住在玉兰这块熟悉不过的地方，买了电瓶车，从益江路到居里路，天天20分钟路，算是很近了，路上听听有声小说。对面就是浦东软件园，是我吃饭的地方，一天两顿。平时基本9点走，周末加班是常事。组内都是年轻人，大多比我大个两三岁，但有的已经四五年经验了。如果现在让我决定的话，宁愿两年经验换两年的烟酒僧生活。挨踢这个行业，经验才是王道，除非你是学术男。会的太杂，深入的太少，一贯的老问题，面试时有几家重技术（百姓、阿里云）的公司都指出了这一点，“要么做产品经理，要么在某个技术上深入下去，否则是很恐怖的事情”。说的时候打击挺大，事后又成了云烟。想学的太多，今天在看php，明天买了mac又扔了php去看IOS开发，问题的根本是什么都想抓住，结果是什么都没能坚持、专注。 关于个人管理。为了改善这种情况，在保持广度的情况下突出深度，需要一些个人管理的方法。现在有了mac和win7双系统，需要一些跨平台的同步工具，evernote作为知识管理是个不错的选择，但之前使用wiz已经积累了很多资料，无法导入到evernote里，且mac下不能用，所以wiz现在也在用，wiz的好处是一些带附件的文档也能够导入。在时间管理方面，使用web版的doit.im作为GTD工具，其在手机端也有相应版本。doit.im有项目视图，我会把一些想做的多步骤才能完成的事情作为一个项目添加，完成该项目的步骤填入，确保不遗忘事情。在深度方面需要改进的是不要铺开N个项目同时进行，每次只针对一个项目，完成以后才能进行下一个项目，算是自己跟自己制定的游戏规则吧。在专注性方面，引入番茄工作法，由于doit.im没有番茄钟的功能，本地的番茄工作法软件又不支持数据云端同步，所以想自己实现一个web版的，这个还需要和熊继续商量。 关于技术。来这边当然是为了学技术，积累项目经验和得到产品级的历练。入职的前两天我在web后端组，搭好了环境准备看代码时却被临时换到symbian组去了，原因是项目紧、缺人。在那边改了一个月的bug，接下来更多的会是小特性的快速迭代，而大的版本变更暂时不会出现，以及改不完的bug和性能调优。当然在适当的时候也会考虑所做工作的价值，因为更核心的web后端才是我真正想做的事情，能得到更多的锻炼，为以后积累更多资本。对大数据量的处理才是互联网企业吸引我的地方，而不是停留在界面的修改、业务逻辑上的打打闹闹。这方面目前还没有积累，我希望自己能在业余时间抽出时间来积累，而不是都将时间卖给游戏和没意义的加班。 除了为将来的工作打基础，我希望自己能在业余时间接触一些开源项目，读一些源代码，自己试着编译和修改。能在业余时间做出一些自己的项目，出于兴趣，不受时间和产品经理的压力。在内功方面需要持之以恒的修炼，计划及方案都有，只剩下执行力了。会把能不能发布技术blog作为检验自己是否真正理解的标准。当然，现在参与的项目也力求总结出一些独立于项目本身的经验，强哥称之为智慧的东西。 关于身体。前段时间本科同一级的一位女生癌症去世了，在感慨生命脆弱的同时，也为自己敲响警钟。一天14+个小时对着电脑（公司+宿舍），伤不起啊。受条件所限，每天都要坚持做下俯卧撑和仰卧起坐。 其他种种，不多说了。关于工作有几句话说的不错，分享下： 为自己工作 以结果为导向 共生而不是堕化 挖掘自身的价值]]></description>
			<content:encoded><![CDATA[<p>从入职到现在差不多一个月的时间。只不过是在大半年的张江男生活上又增添了一个月而已，没有什么新奇的地方。由于有过另外两家公司的实习经历，所以难免在工作中会进行些比对。不再是打酱油的实习生，而是需要产出的劳动者，辛苦是自然的，能学到东西是唯一的期许，薪资福利等等不在重点考虑范围。互联网行业，不慎落入LBS的从业人员。业务上的事情需要关注，但不需过多掺杂，有没有钱途不是我说了算，当然愿景是美好的。作为一名入司不久的新人，挨好你的踢才是根本，其他神马都是浮云。<br />
跟两同学住在玉兰这块熟悉不过的地方，买了电瓶车，从益江路到居里路，天天20分钟路，算是很近了，路上听听有声小说。对面就是浦东软件园，是我吃饭的地方，一天两顿。平时基本9点走，周末加班是常事。组内都是年轻人，大多比我大个两三岁，但有的已经四五年经验了。如果现在让我决定的话，宁愿两年经验换两年的烟酒僧生活。挨踢这个行业，经验才是王道，除非你是学术男。会的太杂，深入的太少，一贯的老问题，面试时有几家重技术（百姓、阿里云）的公司都指出了这一点，“要么做产品经理，要么在某个技术上深入下去，否则是很恐怖的事情”。说的时候打击挺大，事后又成了云烟。想学的太多，今天在看php，明天买了mac又扔了php去看IOS开发，问题的根本是什么都想抓住，结果是什么都没能坚持、专注。</p>
<p><strong>关于个人管理。</strong>为了改善这种情况，在保持广度的情况下突出深度，需要一些个人管理的方法。现在有了mac和win7双系统，需要一些跨平台的同步工具，evernote作为知识管理是个不错的选择，但之前使用wiz已经积累了很多资料，无法导入到evernote里，且mac下不能用，所以wiz现在也在用，wiz的好处是一些带附件的文档也能够导入。在时间管理方面，使用web版的doit.im作为GTD工具，其在手机端也有相应版本。doit.im有项目视图，我会把一些想做的多步骤才能完成的事情作为一个项目添加，完成该项目的步骤填入，确保不遗忘事情。在深度方面需要改进的是不要铺开N个项目同时进行，每次只针对一个项目，完成以后才能进行下一个项目，算是自己跟自己制定的游戏规则吧。在专注性方面，引入番茄工作法，由于doit.im没有番茄钟的功能，本地的番茄工作法软件又不支持数据云端同步，所以想自己实现一个web版的，这个还需要和熊继续商量。</p>
<p><strong>关于技术。</strong>来这边当然是为了学技术，积累项目经验和得到产品级的历练。入职的前两天我在web后端组，搭好了环境准备看代码时却被临时换到symbian组去了，原因是项目紧、缺人。在那边改了一个月的bug，接下来更多的会是小特性的快速迭代，而大的版本变更暂时不会出现，以及改不完的bug和性能调优。当然在适当的时候也会考虑所做工作的价值，因为更核心的web后端才是我真正想做的事情，能得到更多的锻炼，为以后积累更多资本。对大数据量的处理才是互联网企业吸引我的地方，而不是停留在界面的修改、业务逻辑上的打打闹闹。这方面目前还没有积累，我希望自己能在业余时间抽出时间来积累，而不是都将时间卖给游戏和没意义的加班。<br />
除了为将来的工作打基础，我希望自己能在业余时间接触一些开源项目，读一些源代码，自己试着编译和修改。能在业余时间做出一些自己的项目，出于兴趣，不受时间和产品经理的压力。在内功方面需要持之以恒的修炼，计划及方案都有，只剩下执行力了。会把能不能发布技术blog作为检验自己是否真正理解的标准。当然，现在参与的项目也力求总结出一些独立于项目本身的经验，强哥称之为智慧的东西。</p>
<p><strong>关于身体。</strong>前段时间本科同一级的一位女生癌症去世了，在感慨生命脆弱的同时，也为自己敲响警钟。一天14+个小时对着电脑（公司+宿舍），伤不起啊。受条件所限，每天都要坚持做下俯卧撑和仰卧起坐。</p>
<p>其他种种，不多说了。关于工作有几句话说的不错，分享下：</p>
<ol>
<li>为自己工作</li>
<li>以结果为导向</li>
<li>共生而不是堕化</li>
<li>挖掘自身的价值</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2011/08/07/%e5%b7%a5%e4%bd%9c%e4%b8%80%e6%9c%88%e5%b0%8f%e8%ae%b0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>symbian学习笔记三（内存管理）</title>
		<link>http://www.xiaojiayi.com/2011/08/01/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b8%89%ef%bc%88%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86%ef%bc%89/</link>
		<comments>http://www.xiaojiayi.com/2011/08/01/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b8%89%ef%bc%88%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86%ef%bc%89/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 12:12:48 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[symbian]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=168</guid>
		<description><![CDATA[本文内容非原创，属于网上资源的整理。 ======================================== 二阶段构造 问题1：为什么需要二阶段构造？ 首先考虑如下的语句： CClassName* ptr = new (ELeave) CClassName();   在内存有足够空间的情况下，代码首先在堆上分配一个CClassName类型的对象，并将地址赋给ptr指针，然后调用类的构造函数初始化这个对象。 这样，如果类的构造函数出现了异常，则会发生问题，这种异常发生时没有任何指针指向成功分配给CClassName对象的内存区域，因此这些内存成为孤立内存，发生内存泄漏。这就引出了symbian内存处理的一个重要规则：构造函数绝对不能异常退出。 问题2：为什么二阶段函数能够避免内存泄漏？ 二阶段构造函数，顾名思义就是将一个对象的构造分为两个阶段： 第一个阶段是常规的的构造函数，在该构造函数中，没有可能导致异常退出的代码； 第二个阶段是可能会产生异常的构造阶段，实现为函数ConstructL()； 这样，对象的构造过程就应当包括了如下的代码： CClassName* self = new (ELeave) CClassName();    CleanupStack::PushL(self);    self-&#62;ConstructL();    CleanupStack::Pop(self);   这样的构造方式为什么就能够避免内存泄漏呢？下面我们来逐行分析代码： CClassName* self = new (ELeave) CClassName();   重载的运算符new首先将内存分配给新的self实例，如果分配失败，那么程序异常退出，如果成功给新的对象分配了内存，那么接着执行不会异常退出的第一阶段构造函数； CleanupStack::PushL(self);   接着我们将本地指针self推入清除栈，因为下面要调用可能发生异常的退出函数。 self-&#62;ConstructL();   如果该二阶段构造函数在执行时异常退出，那么新的CClassName的指针由清楚栈负责清楚，避免了内存泄漏；另外，如果该函数没有异常退出，则拥有了一个完全构造的CClassName实例。 CleanupStack::Pop(self);   安全的将本地指针从清除栈中弹出； 每实例化一个对象就要写上述代码确实有些啰嗦了，Symbian OS为了简化实例化的步骤，又引入了NewL(),NewLC()两个函数(其实也可以写成一个NewL(),然而大家都比较推崇同时创建NewL()和NewLC())，其具体的实现方式见问题3； 问题3：如何在新的类中创建二阶段构造函数？ .h头文件： Class CClassName : public CBase    {    public:           static CClassName* NewL();           static CClassName* NewlC();           ~CClassName();    private:           CClassName(); //第一阶段构造           void ConstructL(); //第二阶段构造    ……    }   cpp源文件: [...]]]></description>
			<content:encoded><![CDATA[<div>
<p>本文内容非原创，属于网上资源的整理。</p>
<p>========================================</p>
</div>
<div><span class="Apple-style-span" style="color: #0000ff; font-size: small;"><strong>二阶段构造</strong></span></div>
<div><span class="Apple-style-span" style="color: #a52a00;">问题1：为什么需要二阶段构造？</span></div>
<div>
<div>首先考虑如下的语句：</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CClassName* ptr = </span><span class="keyword">new</span><span> (ELeave) CClassName();  </span></span></li>
</ol>
</div>
<div>在内存有足够空间的情况下，代码首先在堆上分配一个CClassName类型的对象，并将地址赋给ptr指针，然后调用类的构造函数初始化这个对象。</div>
<div>这样，如果类的构造函数出现了异常，则会发生问题，这种异常发生时没有任何指针指向成功分配给CClassName对象的内存区域，因此这些内存成为孤立内存，发生内存泄漏。这就引出了symbian内存处理的一个重要规则：构造函数绝对不能异常退出。</div>
<div><span style="color: #a52a00;">问题2：为什么二阶段函数能够避免内存泄漏？</span></div>
<div>二阶段构造函数，顾名思义就是将一个对象的构造分为两个阶段：</div>
<div>第一个阶段是常规的的构造函数，在该构造函数中，没有可能导致异常退出的代码；</div>
<div>第二个阶段是可能会产生异常的构造阶段，实现为函数ConstructL()；</div>
<div>这样，对象的构造过程就应当包括了如下的代码：</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CClassName* self = </span><span class="keyword">new</span><span> (ELeave) CClassName();   </span></span></li>
<li><span>CleanupStack::PushL(self);   </span></li>
<li class="alt"><span>self-&gt;ConstructL();   </span></li>
<li><span>CleanupStack::Pop(self);  </span></li>
</ol>
</div>
<div>这样的构造方式为什么就能够避免内存泄漏呢？下面我们来逐行分析代码：</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CClassName* self = </span><span class="keyword">new</span><span> (ELeave) CClassName();  </span></span></li>
</ol>
</div>
<div>重载的运算符new首先将内存分配给新的self实例，如果分配失败，那么程序异常退出，如果成功给新的对象分配了内存，那么接着执行不会异常退出的第一阶段构造函数；</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CleanupStack::PushL(self);  </span></span></li>
</ol>
</div>
<div>接着我们将本地指针self推入清除栈，因为下面要调用可能发生异常的退出函数。</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>self-&gt;ConstructL();  </span></span></li>
</ol>
</div>
<div>如果该二阶段构造函数在执行时异常退出，那么新的CClassName的指针由清楚栈负责清楚，避免了内存泄漏；另外，如果该函数没有异常退出，则拥有了一个完全构造的CClassName实例。</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CleanupStack::Pop(self);  </span></span></li>
</ol>
</div>
<div>安全的将本地指针从清除栈中弹出；</div>
<div>每实例化一个对象就要写上述代码确实有些啰嗦了，Symbian OS为了简化实例化的步骤，又引入了NewL(),NewLC()两个函数(其实也可以写成一个NewL(),然而大家都比较推崇同时创建NewL()和NewLC())，其具体的实现方式见问题3；</div>
<div><span style="color: #a52a00;">问题3：如何在新的类中创建二阶段构造函数？</span></div>
<div>.h头文件：</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>Class CClassName : </span><span class="keyword">public</span><span> CBase   </span></span></li>
<li><span>{   </span></li>
<li class="alt"><span class="keyword">public</span><span>:   </span></li>
<li><span>       </span><span class="keyword">static</span><span> CClassName* NewL();   </span></li>
<li class="alt"><span>       </span><span class="keyword">static</span><span> CClassName* NewlC();   </span></li>
<li><span>       ~CClassName();   </span></li>
<li class="alt"><span class="keyword">private</span><span>:   </span></li>
<li><span>       CClassName(); </span><span class="comment">//第一阶段构造 </span><span>  </span></li>
<li class="alt"><span>       </span><span class="keyword">void</span><span> ConstructL(); </span><span class="comment">//第二阶段构造 </span><span>  </span></li>
<li><span>……   </span></li>
<li class="alt"><span>}  </span></li>
</ol>
</div>
<div>cpp源文件:</div>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CClassName* CClassName::NewL()   </span></span></li>
<li><span>{   </span></li>
<li class="alt"><span>       CClassName* self = CClassName::NewLC();   </span></li>
<li><span>       CleanupStack::Pop(self);   </span></li>
<li class="alt"><span>       </span><span class="keyword">return</span><span> self;   </span></li>
<li><span>}   </span></li>
<li class="alt"><span>CClassName* CClassName::NewLC()   </span></li>
<li><span>{   </span></li>
<li class="alt"><span>       CClassName* self = </span><span class="keyword">new</span><span> (ELeave) CClassName();   </span></li>
<li><span>       CleanupStack::PushL(self);   </span></li>
<li class="alt"><span>       self-&gt;ConstructL(); </span><span class="comment">//二阶段构造 </span><span>  </span></li>
<li><span>       </span><span class="keyword">return</span><span> self;   </span></li>
<li class="alt"><span>}   </span></li>
<li><span class="keyword">void</span><span> CClassName::ConstructL()   </span></li>
<li class="alt"><span>{   </span></li>
<li><span class="comment">/**************可能产生异常的代码************/</span><span>  </span></li>
<li class="alt"><span>}  </span></li>
</ol>
<div>
<div align="left"><strong><span style="color: #0000ff;">Why Memory Management</span></strong></div>
<div align="left">    <a href="http://www.sf.org.cn/symbian-os.html" target="_blank">Symbian OS</a>本身就是为<a title="家电维修 电子技术 电脑知识@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=2473&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.zfjd.cn&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=802405&amp;k=%E5%86%85%E5%AD%98" target="_blank">内存</a>和<a title="你放代码我付钱1@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=5143&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.vogate.com/flow2.php&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=210306&amp;k=%E8%B5%84%E6%BA%90" target="_blank">资源</a>受限的设备开发的，应用<a title="中国站长－我要做属于自己的网站@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=4744&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.cnzz.cn&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=436188&amp;k=%E7%A8%8B%E5%BA%8F" target="_blank">程序</a>运行过程中很可能碰到内存用光，或者<a title="维博电脑信息网@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=6038&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.weibo800.cn&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=638529&amp;k=%E7%A1%AC%E4%BB%B6" target="_blank">硬件</a>资源不可用的情况。而这种exceptions是通过修改程序无法解决的，所以遵守以下几条：</div>
<ul type="disc">
<li>尽量不要<a title="校内网代码@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=5383&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//biyela.net&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=167752&amp;k=%E4%BD%BF%E7%94%A8" target="_blank">使用</a>不必要的RAM</li>
<li>尽早释放资源，如文件server等</li>
<li>当你每次申请内存时，都须准备处理out-of-memory错误</li>
<li>当 out-of-memory错误发生时，返回到<a title="中国红娘-真实严肃的婚恋交友平台@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=5373&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.hongniang.com&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=378695&amp;k=%E4%B8%80%E4%B8%AA" target="_blank">一个</a>stable的状态，并释放所有期间申请到的资源</li>
</ul>
<div>
<div align="left"><strong><span style="color: #0000ff;"> Stack and Heap</span></strong></div>
<div align="left">    Stack：默认大小8kb，自动删除，如 TInt i = 0;</div>
<div align="left">    Heap ：至少０.5Mb，由程序员手动删除，如 CMyObj* obj = new (ELeave) CMyObj;</div>
<div align="left"><strong><span style="color: #0000ff;">Leaves</span></strong></div>
<div align="left">    首先介绍Conventional C++ Memory Management，在Symbian看来，这是非常低效率的。</div>
<ul type="disc">
<li>NULL Pointer Checking  if ((myObj = new CMyObj( ) ) == NULL) { //Error Handling }</li>
<li>ANSI C++ Exeption Handling   try { //throw an Exception } catch (int e) { //Error Handling }</li>
</ul>
<div align="left">    在Symbian中<a title="各种行业研究报告！！一网打尽@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=5301&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//bbs.21our.com&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=465235&amp;k=%E6%8E%A8%E8%8D%90" target="_blank">推荐</a><a title="网络电视在线看@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=755&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.cntvs.net&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=260104&amp;k=%E9%87%87%E7%94%A8" target="_blank">采用</a>Leave，如果内存或者资源不能分配到，这个<a title="想成为成功站长？follow me！@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=4864&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.llf535.com/&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=198436&amp;k=%E4%BB%A3%E7%A0%81" target="_blank">代码</a>就会Leave，沿着Call Stack，直到操作系统或者在某个函数中被Handle掉。</div>
<div align="left">    所有可能Leave的函数最好以L结尾，保证该函数的用户知道这个函数可能Leave。</div>
<div align="left">    Leave的例子：</div>
<ul type="disc">
<li>动态内存分配： return new (ELeave) TUint8[1000];</li>
<li>产生一个Leave：User::Leave(KErrNotFound);</li>
<li>内存不足时Leave：User::LeaveNoMemory();</li>
<li>NULL的时候Leave：User::LeaveIfNull(aNotify);</li>
<li>当发生错误时Leave：RFs fs; TInt err = fs.Connect(); User::LeaveIfError(err);</li>
</ul>
<div align="left">    处理Leave：</div>
<div align="left">    操作系统有默认的处理Leave的方式：</div>
<ul type="disc">
<li>在程序启动过程中：直接关闭应用程序。</li>
<li>应用程序启动后：显示一个错误消息。</li>
</ul>
<div align="left">    开发者<a title="你放代码我付钱3@Vogate.com" href="http://action.vogate.com/c/c.php?r=http%3A//www.sf.org.cn/Article/symbiandev/List_12.html&amp;aid=5145&amp;sid=6235007045036118&amp;click=1&amp;url=http%3A//www.vogate.com/flow2.php&amp;v=0&amp;s=http%3A//www.sf.org.cn/Article/symbiandev/200610/19136.html&amp;rn=858573&amp;k=%E5%8F%AF%E4%BB%A5" target="_blank">可以</a>通过trap装置来处理Leave。TRAP(_r, _s)和TRAPD(_r, _s)，其中：</div>
<ul type="disc">
<li>_r：是一个TInt类型的leave code，默认值为TErrNone。</li>
<li>_s：一系列可能Leave的C++ Statements。</li>
</ul>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>TRAPD(err, DoFunctionL());   </span></span></li>
<li><span class="keyword">if</span><span> (err != KErrNone)   </span></li>
<li class="alt"><span>    { </span><span class="comment">//Error Handling } </span><span>  </span></li>
<li><span class="keyword">else</span><span>  </span></li>
<li class="alt"><span>    { </span><span class="comment">//Everything is well }</span><span>  </span></li>
</ol>
</div>
<div align="left"><strong><span style="color: #0000ff;">  The Cleanup Stack</span></strong></div>
<div align="left">    Cleanup stack用于存储在leave发生后需要deallocating的局部变量(指针)。即：当一个函数leave了，所有在cleanup stack上的对象会被全部删除掉。</div>
<div align="left">    Cleanup Stack的使用方法：</div>
<div align="left">CleanupStack::PushL(ptr) ：当发生leave时所有内存都会被释放<br />
CleanupClosePushL(handle)：当发生leave时这个句柄（handler）会被关闭</div>
<div align="left">CleanupStack::Pop(pointer)：第一个元素出栈<br />
CleanupStack::PopAndDestroy(pointer)：第一个元素出栈并释放内存</div>
<div align="left">    如果一个函数可能leave，检查一下两种情况：</div>
<ul type="disc">
<li>如果leave了，是否所有在堆（heap）上的元素都在cleanup stack中了</li>
<li>如果没有leave，你是否自己恰当地将他cleanup了</li>
</ul>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>CMyClass* CMyClass::NewL(TInt aBufSize)   </span></span></li>
<li><span>   {   </span></li>
<li class="alt"><span>   CMyClass* self = </span><span class="keyword">new</span><span> (ELeave) CMyClass;   </span></li>
<li><span>   CleanupStack::PushL(self);   </span></li>
<li class="alt"><span>   self-&gt;ConstructL(aBufSize);   </span></li>
<li><span>   CleanupStack::Pop(self);   </span></li>
<li class="alt"><span>   </span><span class="keyword">return</span><span> self;   </span></li>
<li><span>   }  </span></li>
</ol>
</div>
<div align="left">    如果某个函数会在cleanup stack上留下一个对象，那么他必须以C结尾。</div>
<div align="left"><strong><span style="color: #0000ff;">Two Phase Construction</span></strong></div>
<div align="left">    C++构造函数一定不能leave。所有内存和资源的分配应该在第二阶段构造函数ConstructL( )中完成。</div>
<div align="left">编码指南，所有用户定义的C类必须：</div>
<ul type="disc">
<li>定义NewL和NewLC函数为public static</li>
<li>定义ConstructL和C++ Constructor为private</li>
</ul>
<div align="left"><strong><span style="color: #0000ff;">Best Practise</span></strong></div>
<div align="left">     Construction的规则：</div>
<ul type="disc">
<li>默认的C++构造函数中不能含有可能leave的代码</li>
<li>可能发生leave的函数必须在ConstructL中被调用</li>
<li>如果基类也有ConstructL，必须首先调用，不要忘了explicit scoping</li>
</ul>
<div align="left">    Destruction的规则：</div>
<ul type="disc">
<li>C类必须在析构函数中删除它自己所包含的对象</li>
<li>在删除一个对象后，把它的指针设为NULL</li>
<li>不要删除不是本类所拥有的对象</li>
<li>在reallocation前首先删除对象，并且将其指针设为NULL</li>
</ul>
<div align="left">    Further Discussion：</div>
<ul type="disc">
<li>Preserve Stack Memory：每个进程只有8K，以引用的方式传递参数，大的对象放在堆上</li>
<li>Preallocation vs last moment allocation：一般的原则是只在使用前分配资源并且在使用后马上释放。但是preallocation的好处是节约处理时间，并且在没有内存的情况下照常运行（资源已经分配到了）</li>
<li>where to put trap harness：最基本的情况是依靠GUI应用程序的框架。根据应用的不同，可以自定义粒度。</li>
<li>Error Code Returns vs. leaving functions：在执行某个处理前检测是否会出现问题，如下代码：</li>
</ul>
<div align="left">                                    User::LeaveIfError(fs.Connect());</div>
<div align="left"><strong><span style="color: #0000ff;">Memory Leaks</span></strong></div>
<div align="left">    如果你的程序有内存泄露，在模拟器上关闭时会crash。尽早发现并解决你的内存泄露，因为你可以追查到你可能导致内存泄露的代码改动。如果实在找不到，可用下面方法：</div>
<div align="left">    Heap Balance Checking：</div>
<ul type="disc">
<li>_UHEAP_MARK</li>
<li>_UHEAP_MARKEND</li>
</ul>
<div align="left">    用上述这两个宏放在你要检查的代码的开头和结尾，如果发生panic，则说明这段代码中发生了内存泄露。可以嵌套使用。</div>
<div align="left"><strong><span style="color: #0000ff;">Panics </span></strong></div>
<div align="left">    Panic是一个未经处理的exception，暗示着一个无法解决的错误。</div>
<div align="left">一般程序有以下三类错误：</div>
<ul type="disc">
<li>程序错误：如引用一个超过数组范围的元素</li>
<li>环境错误：内存、磁盘空间不够，或缺少其他资源等</li>
<li>用户错误：输入错误数据</li>
</ul>
<div>    可以使用trap和cleanup stack技术来解决环境和用户错误，但是对于第一类的程序错误，我们无法恢复，最好是使用User::Panic()函数，它带有两个参数，第一个是string，第二个是Tint。</div>
</div>
<div>
<div><span style="color: #ff6820;">内存管理的二十二条军规</span></div>
<div>1、C类必须有析构函数，这是CBase的一个虚函数。<br />
2、C类的构造函数和ConstructL()必须为protect或private类型的成员函数<br />
3、在C class中必须有一个NewLC()函数，除非它是嵌套类。NewL()是可选的，并且总是根据NewLC()来实现。<br />
4、NewL()和NewLC()在c class中必须是static函数。<br />
5、C类通过指针和引用来传递。<br />
6、拷贝构造函数在symbian中没有用。<br />
7、不要一定在析构函数中删除类的成员对象。（生命期结束即可删除）<br />
8、析构函数中必须对对象进行if检查。即</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="keyword">if</span><span>(iObject) </span><span class="keyword">delete</span><span> iObject;iObject = NULL;  </span></span></li>
</ol>
</div>
<p>9、R类没有明确的构造、析构或拷贝构造函数以及赋值操作。<br />
10、delete a;a=NULL;a=b;标准重新分配过程。<br />
11、任何可能导致异常退出的函数皆加L后缀。<br />
12、不要删除非拥有对象（也就是，那些仅仅只使用的对象）<br />
13、分配动态数组前定义一个合适粒度。<br />
14、把new换成new(ELeave).<br />
15、if(函数不能异常退出&amp;&amp;要自己处理错误时)使用TRAP&amp;&amp;不要过多嵌套。<br />
16、if(aObject被一个自动变量指针引用&amp;&amp;将进行一个可能在aObject生存期内Leave的操作）<br />
CleanupStack::PushL(aObject);<br />
17、决不能把一个i前缀的成员变量PushL入清理栈。<br />
18、构造函数决不能Leave，把可能异常退出的语句放到ConstructL()中去。<br />
19、Symbian的默认栈容量为8k，小心使用递归。<br />
20、TBuf的长度最好不超16，必要的情况下用HBufC代替TBuf.<br />
21、使用__UHEAP_MAEK 宏来检测你的内存状况。<br />
22、尽可能早的删除一切失去使用价值的东西，不要等到函数尾部（自动变量）或在析构函数中才删除（成员变量）。</p>
</div>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2011/08/01/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b8%89%ef%bc%88%e5%86%85%e5%ad%98%e7%ae%a1%e7%90%86%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>symbian学习笔记二（字符串）</title>
		<link>http://www.xiaojiayi.com/2011/08/01/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%ba%8c%ef%bc%88%e5%ad%97%e7%ac%a6%e4%b8%b2%ef%bc%89-2/</link>
		<comments>http://www.xiaojiayi.com/2011/08/01/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%ba%8c%ef%bc%88%e5%ad%97%e7%ac%a6%e4%b8%b2%ef%bc%89-2/#comments</comments>
		<pubDate>Mon, 01 Aug 2011 08:18:15 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[symbian]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=128</guid>
		<description><![CDATA[本文内容非原创，属于网上资源的整理。 ======================================== 8位：（TDesC8），用于二进制数据或者ASCII字符串 16位：（TDesC16），默认，Unicode 描述符可以分为五类： 抽象类（Abstract）：（TDes、TDesC、Tdes8、TdesC8），其他描述符的基类，仅提供接口和基本功能，不能被实例化，一般只用作函数的参数。  文字常量（Literal）：（TlitC、_LIT()），用于存储文字字符串（literal string），即C中字符串常量，通常使用_LIT()这种方式（当然还有_L()和_L8()的描述方式，但都不提倡用）。  栈类（Buffer）：（Tbuf、TbufC、 Tbuf8、TbufC8），数据存储于栈上，最基本的描述符变量类型，大小在编译时确定，包含描述符本身数据，使用最为普遍 堆类（Heap）：（HbufC、HbufC8），数据存储于堆上，大小在运行时确定，也就是是用来处理动态申请的描述符类。 指针类（Pointer）：（TPtr、TPtrC、TPtr8、TPtrC8），本身不包含描述符数据，但是包含长度数据，而且还包含一个指向位于描述符之外数据的指针。 1、  文字描述符常量 LIT(KMyFile, &#8220;c:\System\Apps\MyApp\MyFile.jpg&#8221;);   _L()可以生成一个指向字符值的地址（TPtrC），它经常被用来传递字符串到函数中（包括描述符的构造函数和格式化函数）；同理_L8()则可以生成一个指向二进制数据的地址（TPtrC8）举例如下： NEikonEnvironment::MessageBox(_L(&#8220;Error: init file not found!&#8221;));    //数字转字符串    TBuf16&#60;20&#62; buf;    TInt iNum = 20;    buf.Format( _L( &#8220;%d&#8221; ) , iNum  );   2、  栈描述符 LIT(Ktext , &#8220;Test Text&#8221;);    _LIT(Ktext1 , &#8220;Test1 Text&#8221;);    _LIT(KXtraText , &#8220;New:&#8221;);    _LIT(NewText , &#8220;New1&#8243;);    _LIT(NewText1 , &#8220;New2&#8243;);    TBufC&#60;10&#62; Buf1 ( Ktext );//Buf1长度为9 内容 “Test Text”    TBufC&#60;10&#62; Buf2 ( Ktext1 );//Buf2长度为10 内容 “Test1 Text”    // 通过赋值的方式改变数据    Buf2 = Buf1; //Buf2长度变为9 内容 “Test Text”    //通过使用Des()生成指针改变TBufC的数据    TPtr Pointer = Buf1.Des();    // 删除后四个字符    Pointer.Delete(Pointer.Length()-4, 4 ); //Buf1长度变为5 内容“Test ”//但是内存应该没变    // 增加新的数据    [...]]]></description>
			<content:encoded><![CDATA[<p>本文内容非原创，属于网上资源的整理。</p>
<p>========================================</p>
<p><a href="http://www.xiaojiayi.com/wp-content/uploads/2011/08/cfdb8e3b00aa7e6fb9998fd9.jpg"><img class="alignnone size-full wp-image-157" title="1" src="http://www.xiaojiayi.com/wp-content/uploads/2011/08/cfdb8e3b00aa7e6fb9998fd9.jpg" alt="" width="635" height="689" /></a></p>
<p><a href="http://www.xiaojiayi.com/wp-content/uploads/2011/08/a3b3aa30c8e67cb31b4cffa13.jpg"><img class="alignnone size-full wp-image-160" title="2" src="http://www.xiaojiayi.com/wp-content/uploads/2011/08/a3b3aa30c8e67cb31b4cffa13.jpg" alt="" width="574" height="508" /></a></p>
<ul>
<li>8位：（TDesC8），用于二进制数据或者ASCII字符串</li>
<li>16位：（TDesC16），默认，Unicode</li>
</ul>
<div><a href="http://www.xiaojiayi.com/wp-content/uploads/2011/08/32.jpg"><img class="alignnone size-full wp-image-161" title="3" src="http://www.xiaojiayi.com/wp-content/uploads/2011/08/32.jpg" alt="" width="468" height="243" /></a></div>
<p align="left">描述符可以分为五类：</p>
<ol start="1">
<li>抽象类（Abstract）：（TDes、TDesC、Tdes8、TdesC8），其他描述符的基类，仅提供接口和基本功能，不能被实例化，一般只用作函数的参数。</li>
<li> 文字常量（Literal）：（TlitC、_LIT()），用于存储文字字符串（literal string），即C中字符串常量，通常使用_LIT()这种方式（当然还有_L()和_L8()的描述方式，但都不提倡用）。</li>
<li> 栈类（Buffer）：（Tbuf、TbufC、 Tbuf8、TbufC8），数据存储于栈上，最基本的描述符变量类型，大小在编译时确定，包含描述符本身数据，使用最为普遍</li>
<li>堆类（Heap）：（HbufC、HbufC8），数据存储于堆上，大小在运行时确定，也就是是用来处理动态申请的描述符类。</li>
<li>指针类（Pointer）：（TPtr、TPtrC、TPtr8、TPtrC8），本身不包含描述符数据，但是包含长度数据，而且还包含一个指向位于描述符之外数据的指针。</li>
</ol>
<p align="left">1、  文字描述符常量</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>LIT(KMyFile, </span><span class="string">&#8220;c:\System\Apps\MyApp\MyFile.jpg&#8221;</span><span>);  </span></span></li>
</ol>
</div>
<p align="left">_L()可以生成一个指向字符值的地址（TPtrC），它经常被用来传递字符串到函数中（包括描述符的构造函数和格式化函数）；同理_L8()则可以生成一个指向二进制数据的地址（TPtrC8）举例如下：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>NEikonEnvironment::MessageBox(_L(</span><span class="string">&#8220;Error: init file not found!&#8221;</span><span>));   </span></span></li>
<li><span class="comment">//数字转字符串 </span><span>  </span></li>
<li class="alt"><span>TBuf16&lt;20&gt; buf;   </span></li>
<li><span>TInt iNum = 20;   </span></li>
<li class="alt"><span>buf.Format( _L( </span><span class="string">&#8220;%d&#8221;</span><span> ) , iNum  );  </span></li>
</ol>
</div>
<p align="left">2、  栈描述符</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>LIT(Ktext , </span><span class="string">&#8220;Test Text&#8221;</span><span>);   </span></span></li>
<li><span>_LIT(Ktext1 , </span><span class="string">&#8220;Test1 Text&#8221;</span><span>);   </span></li>
<li class="alt"><span>_LIT(KXtraText , </span><span class="string">&#8220;New:&#8221;</span><span>);   </span></li>
<li><span>_LIT(NewText , </span><span class="string">&#8220;New1&#8243;</span><span>);   </span></li>
<li class="alt"><span>_LIT(NewText1 , </span><span class="string">&#8220;New2&#8243;</span><span>);   </span></li>
<li><span>TBufC&lt;10&gt; Buf1 ( Ktext );</span><span class="comment">//Buf1长度为9 内容 “Test Text” </span><span>  </span></li>
<li class="alt"><span>TBufC&lt;10&gt; Buf2 ( Ktext1 );</span><span class="comment">//Buf2长度为10 内容 “Test1 Text” </span><span>  </span></li>
<li><span class="comment">// 通过赋值的方式改变数据 </span><span>  </span></li>
<li class="alt"><span>Buf2 = Buf1; </span><span class="comment">//Buf2长度变为9 内容 “Test Text” </span><span>  </span></li>
<li><span class="comment">//通过使用Des()生成指针改变TBufC的数据 </span><span>  </span></li>
<li class="alt"><span>TPtr Pointer = Buf1.Des();   </span></li>
<li><span class="comment">// 删除后四个字符 </span><span>  </span></li>
<li class="alt"><span>Pointer.Delete(Pointer.Length()-4, 4 ); </span><span class="comment">//Buf1长度变为5 内容“Test ”//但是内存应该没变 </span><span>  </span></li>
<li><span class="comment">// 增加新的数据 </span><span>  </span></li>
<li class="alt"><span>Pointer.Append(KXtraText);</span><span class="comment">//Buf1长度为9 内容为“Test New：” </span><span>  </span></li>
<li><span class="comment">// 也可以使用下列方式改变数据 </span><span>  </span></li>
<li class="alt"><span>TBufC&lt;10&gt; Buf3(NewText);   </span></li>
<li><span>Pointer.Copy(Buf3);</span><span class="comment">//Buf1长度为4，内容为New1 </span><span>  </span></li>
<li class="alt"><span class="comment">// 或直接从字符串里获得数据 </span><span>  </span></li>
<li><span>Pointer.Copy(NewText1);</span><span class="comment">//Buf1长度为4，内容为New2</span><span>  </span></li>
</ol>
</div>
<p align="left">    以上介绍的是不可修改的栈描述符，而可修改的描述符就不用通过那么复杂的方法来实现修改，它直接可以用Copy、Delete等方法，但是无论可修改的还是不可修改的，一旦指定最大的数据长度后，最大长度就不能进行修改了。</p>
<p align="left">在内存中如下所示:</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>TBuf&lt;16&gt; helloWorld = KHelloWorld; TInt len = KHelloWorld().Length(); helloWorld[len-1]=&#8217;?';  </span></span></li>
</ol>
</div>
<p align="left">TBufC的用法如下：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>_LIT(KHelloWorld, </span><span class="string">&#8220;Hello World&#8221;</span><span>); </span><span class="keyword">const</span><span> TInt maxBuf = 32; TBufCbuf; TInt currentLen = buf.Length(); </span><span class="comment">// == 0 buf = KHelloWorld; currentLen = buf.Length(); // == 11 TText ch = buf[2]; // == &#8217;l&#8217;</span><span>  </span></span></li>
</ol>
</div>
<p align="left"> TBuf的用法如下：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="keyword">const</span><span> TInt bufLen = 6; TUInt8 objType = 1; TUInt8 objId = 1; TUInt8 xCoord = 128; TUInt8 yCoord = 192; &#8230;. TBuf8&lt;bufLen&gt; buf; buf.Append(objType); buf.Append(objId); &#8230; </span><span class="comment">//we can now do something with the buffer such as writting it to a binary file or send via socket.</span><span>  </span></span></li>
</ol>
</div>
<p align="left">3、  堆描述符</p>
<p align="left">堆描述符虽然都是不可修改类型的，但是它仍然具有构造和修改，与栈描述符不同的是：首先对内存需要显示释放，其次是堆描述符没有最大长度的限制，任何时候都可以用ReAlloc（）函数重新申请分配。具体见示例：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="comment">//例1、构造 </span><span>  </span></span></li>
<li><span class="comment">//有两种方式来生成一个Heap Descriptor </span><span>  </span></li>
<li class="alt"><span class="comment">//第一种方式用New(),NewL(),或NewLC() </span><span>  </span></li>
<li><span class="comment">//如下操作便可以构建一个存放数据的空间，空间为15，不过目前大小为0 </span><span>  </span></li>
<li class="alt"><span>HBufC * Buf = HBufC::NewL(15);   </span></li>
<li><span class="comment">//第二种方式是采用Alloc()，AllocL()或AllcLC()来处理， </span><span>  </span></li>
<li class="alt"><span class="comment">//不过这是已经存在的数据的管理方式。新的Heap Descriptor </span><span>  </span></li>
<li><span class="comment">//可以自动的根据这个内容来构造。 </span><span>  </span></li>
<li class="alt"><span>_LIT (KText , </span><span class="string">&#8220;Test Text&#8221;</span><span>);   </span></li>
<li><span>TBufC&lt;10&gt;  CBuf = KText;   </span></li>
<li class="alt"><span>HBufC * Buf1 = CBuf.AllocL();   </span></li>
<li><span>CleanupStack::PushL(Buf1);   </span></li>
<li class="alt"><span class="comment">//例2、修改 </span><span>  </span></li>
<li><span class="comment">//下面是通过赋值方式改变其数据的方法 </span><span>  </span></li>
<li class="alt"><span>_LIT ( KText1 , </span><span class="string">&#8220;Text1&#8243;</span><span>);   </span></li>
<li><span>*Buf1 = KText1;   </span></li>
<li class="alt"><span class="comment">// 通过可修改指针来改变数据的方式 </span><span>  </span></li>
<li><span>TPtr Pointer = Buf1-&gt;Des();   </span></li>
<li class="alt"><span class="comment">//添加数据 </span><span>  </span></li>
<li><span>Pointer.Delete(Pointer.Length() - 2, 2);   </span></li>
<li class="alt"><span class="comment">//删除数据 </span><span>  </span></li>
<li><span>_LIT ( KNew, </span><span class="string">&#8220;New:&#8221;</span><span>);   </span></li>
<li class="alt"><span>Pointer.Append(KNew);   </span></li>
<li><span class="comment">//例3、重新申请内存 </span><span>  </span></li>
<li class="alt"><span>Buf1 = Buf1-&gt;ReAllocL(KText().Length() + KNew().Length());   </span></li>
<li><span>CleanupStack::PushL(Buf1);   </span></li>
<li class="alt"><span class="comment">//例4、释放内存 </span><span>  </span></li>
<li><span class="comment">//直接用delete </span><span>  </span></li>
<li class="alt"><span class="keyword">delete</span><span> Buf;   </span></li>
<li><span>Buf = NULL;   </span></li>
<li class="alt"><span class="comment">//如果在使用NewL、ReAllocL等异常函数后我们使用清除栈压入的话 </span><span>  </span></li>
<li><span class="comment">//那么我们也可以用清除栈来释放内存 </span><span>  </span></li>
<li class="alt"><span>CleanupStack::PopAndDestroy();   </span></li>
<li><span>Buf1 = NULL;  </span></li>
</ol>
</div>
<p align="left">注：关于以上用清除栈的方式，个人只是猜测，因为对Symbian的异常处理三部曲，至今仍没有很好的掌握，所以如果有什么误用还望指点。</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>HBufC* heapBuf = HBufC::NewL(KHelloWorld().Length()); *heapBuf = KHelloWorld(); </span><span class="keyword">delete</span><span> heapBuf;  </span></span></li>
</ol>
</div>
<p align="left">     在内存中的情况如下图所示：</p>
<p align="left">    HBufC通常在以下几种情况下使用：</p>
<ul>
<li> 在运行时从资源文件中加载字符串</li>
<li> 从用户界面中接收用户输入的字符串</li>
<li>从应用程序引擎中接收字符串，如contacts database中的名字</li>
</ul>
<p align="left">     对HBufC中的内容进行修改：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>HBufC* heapBuf = HBufC::NewL(KHelloWorld().Length()); *heapBuf = KHelloWorld(); </span><span class="keyword">delete</span><span> heapBuf;  </span></span></li>
</ol>
</div>
<p align="left">4、  指针描述符</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="comment">//例1、用TBuf和TBufC构造出TPtrC对象 </span><span>  </span></span></li>
<li><span>_LIT(KText , </span><span class="string">&#8220;Test Code&#8221;</span><span>);   </span></li>
<li class="alt"><span>TBufC&lt;10&gt; Buf ( KText );   </span></li>
<li><span class="comment">//或者为 TBuf&lt;10&gt; Buf ( KText ); </span><span>  </span></li>
<li class="alt"><span class="comment">// Creation of TPtrC using Constructor </span><span>  </span></li>
<li><span>TPtrC  Ptr (Buf);   </span></li>
<li class="alt"><span class="comment">// Creation of TPtrC using Member Function </span><span>  </span></li>
<li><span>TPtrC     Ptr1;   </span></li>
<li class="alt"><span>Ptr1.Set(Buf);   </span></li>
<li><span class="comment">//例2、用TText*构造TPtrC </span><span>  </span></li>
<li class="alt"><span class="keyword">const</span><span> TText* text = _S(</span><span class="string">&#8220;Hello World\n&#8221;</span><span>);   </span></li>
<li><span>TPtrC ptr(text);   </span></li>
<li class="alt"><span class="comment">// 或者 </span><span>  </span></li>
<li><span>TPtrC Ptr2;   </span></li>
<li class="alt"><span>Ptr2.Set(text);   </span></li>
<li><span class="comment">//如果要存储TText的一部分数据，我们使用下列方法 </span><span>  </span></li>
<li class="alt"><span>TPtrC   ptr4(text, 5);   </span></li>
<li><span class="comment">//例3、从另一个TPtrC中构造TPtrC </span><span>  </span></li>
<li class="alt"><span class="keyword">const</span><span> TText * text1 = _S(</span><span class="string">&#8220;Hello World\n&#8221;</span><span>);   </span></li>
<li><span>TPtrC Ptr3(text1);   </span></li>
<li class="alt"><span class="comment">// 从一个TPtrC中获得另一个TPtrC </span><span>  </span></li>
<li><span>TPtrC p1(Ptr3);   </span></li>
<li class="alt"><span class="comment">// 或 </span><span>  </span></li>
<li><span>TPtrC p2;   </span></li>
<li class="alt"><span>p2.Set(Ptr3);  </span></li>
</ol>
</div>
<p align="left">以上是不可修改的TPtrC的构造，相对应的也有可修改的TPtr的构造，不过我们下面省略了用Set()函数的构造方法</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span> </span><span class="comment">//例1、通过TBufC,HBufC的Des()方法获取 </span><span>  </span></span></li>
<li><span>_LIT(KText, </span><span class="string">&#8220;Test Data&#8221;</span><span>);   </span></li>
<li class="alt"><span>TBufC&lt;10&gt; NBuf ( KText );   </span></li>
<li><span>TPtr Pointer = NBuf.Des();   </span></li>
<li class="alt"><span class="comment">//例2、通过指定内存区域和大小来生成 </span><span>  </span></li>
<li><span class="keyword">const</span><span> TText * Text = _S(</span><span class="string">&#8220;Test Second&#8221;</span><span>);   </span></li>
<li class="alt"><span>TPtr Pointer1((TText*)Text, 11, 12);   </span></li>
<li><span class="comment">//例3、 通过另一个TPtr对象来生成 </span><span>  </span></li>
<li class="alt"><span>TPtr Pointer2 ( Pointer );  </span></li>
</ol>
</div>
<p align="left">对于可修改的TPtr虽然前面用过，但是我们在这里在简单的添加两个例子加深下印象，并且说明指针修改的始终是它指向的描述符：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="comment">//例1、改变已有TPtr数据的方式：赋值和Copy()方法 </span><span>  </span></span></li>
<li><span>_LIT(KText, </span><span class="string">&#8220;Test Data&#8221;</span><span>);   </span></li>
<li class="alt"><span>_LIT(K1, </span><span class="string">&#8220;Text1&#8243;</span><span>);   </span></li>
<li><span>_LIT(K2, </span><span class="string">&#8220;Text2&#8243;</span><span>);   </span></li>
<li class="alt"><span>TBufC&lt;10&gt; NBuf ( KText );</span><span class="comment">//NBuf内容为“Test Data” </span><span>  </span></li>
<li><span>TPtr Pointer = NBuf.Des(); </span><span class="comment">//Pointer指向NBuf的内容 </span><span>  </span></li>
<li class="alt"><span>Pointer = K1; </span><span class="comment">// NBuf内容为“Text1” </span><span>  </span></li>
<li><span>Pointer.Copy(K2); </span><span class="comment">// NBuf内容为“Text2” </span><span>  </span></li>
<li class="alt"><span class="comment">//例2、直接通过修改长度改变数据内容 </span><span>  </span></li>
<li><span>Pointer.SetLength(2); </span><span class="comment">// NBuf内容为&#8221;Te&#8221; 注：实际内存的内容应该没变 </span><span>  </span></li>
<li class="alt"><span class="keyword">const</span><span> unsigned </span><span class="datatypes">char</span><span> KBuffer[ ] = {0&#215;00, 0&#215;33, 0&#215;66, 0&#215;99, 0xbb, 0xff}; TPtrC8 bufferPtr( KBuffer, </span><span class="keyword">sizeof</span><span>(KBuffer)); iSocket.Write(bufferPtr, iStatus);  </span></li>
</ol>
</div>
<p align="left">在内存中如下所示：</p>
<p align="left"><a href="http://www.xiaojiayi.com/wp-content/uploads/2011/08/4.jpg"><img class="alignnone size-full wp-image-162" title="4" src="http://www.xiaojiayi.com/wp-content/uploads/2011/08/4.jpg" alt="" width="678" height="195" /></a></p>
<p align="left">TPtr的用法：</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>_LIT(KHelloWorld, </span><span class="string">&#8220;Hello World&#8221;</span><span>); </span><span class="keyword">const</span><span> TInt maxBuf = 32; TBufC&lt;maxBuf&gt; buf; buf = KHelloWorld; TPtr ptr = buf.Des(); ptr[7] = &#8217;a';  ptr[8] = &#8217;l';  ptr[9] = &#8217;e';  ptr[10] = &#8217;s'; CEikonEnv::Static()-&gt;InfoMsg(ptr); </span><span class="comment">// &#8221;Hello Wales&#8221;</span><span>  </span></span></li>
</ol>
</div>
<p align="left">5、  抽象描述符</p>
<p align="left">抽象描述符，没有什么好说的，正如前面所说，只用在函数的形参中，通常要强调参数是不可修改的，就用const TDesC&amp;表示，可修改的参数用TDesC&amp;表示。</p>
<ul>
<li>在函数参数中尽量使用基类</li>
<li>使用中性的描述符，一般情况下使用TDesC而不是TDesC8或者TDesC16</li>
<li>当描述符内容不应该改变时，使用const修饰符</li>
<li>经典用法：void SetText(const TDesC&amp; aText);    TPtrC Text() const;</li>
</ul>
<p align="left">描述符之间的转换</p>
<p align="left"><strong>不可修改向可修改描述符的转换</strong></p>
<p align="left">原则1：通过不可修改描述符类内的Des()函数，将不可修改的描述符转换成可修改的指针描述符</p>
<p align="left">示例1：TBufC转换成TPtr</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>_LIT(KText, </span><span class="string">&#8220;Test Data&#8221;</span><span>);   </span></span></li>
<li><span>TBufC&lt;10&gt; NBuf ( KText );   </span></li>
<li class="alt"><span>TPtr Pointer = NBuf.Des();  </span></li>
</ol>
</div>
<p align="left">示例2：HBufC转换成TPtr</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span>HBufC * Buf = HBufC::NewL(15);   </span></span></li>
<li><span>_LIT (KText , </span><span class="string">&#8220;Test Text&#8221;</span><span>);   </span></li>
<li class="alt"><span>*Buf = KText;   </span></li>
<li><span>TPtr Pointer = Buf-&gt;Des();  </span></li>
</ol>
</div>
<p align="left">原则2：通过TPtr的构造函数或Set()函数可以将TPtrC描述转换为可修改的指针描述符</p>
<p align="left">示例3：TPtrC到TPtr</p>
<div class="dp-highlighter">
<ol class="dp-cpp">
<li class="alt"><span><span class="keyword">const</span><span> TText * text1 = _S(</span><span class="string">&#8220;Hello World\n&#8221;</span><span>);   </span></span></li>
<li><span>TPtrC Ptr1(text1);   </span></li>
<li class="alt"><span>TPtrC Ptr2(Ptr1);   </span></li>
<li><span class="comment">//可以通过构造函数 </span><span>  </span></li>
<li class="alt"><span>TPtr Ptr3((TUint16 *)(Ptr1.Ptr()), Ptr1.Length());   </span></li>
<li><span class="comment">//也可以通过Set()函数 </span><span>  </span></li>
<li class="alt"><span>Ptr3.Set((TUint16 *)(Ptr1.Ptr()),Ptr1.Length(), Ptr1.Length());  </span></li>
</ol>
</div>
<p align="left">
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2011/08/01/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%ba%8c%ef%bc%88%e5%ad%97%e7%ac%a6%e4%b8%b2%ef%bc%89-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>symbian学习笔记一（基本数据类型及命名规范）</title>
		<link>http://www.xiaojiayi.com/2011/07/27/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b8%80%ef%bc%88%e5%9f%ba%e6%9c%ac%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e5%8f%8a%e5%91%bd%e5%90%8d%e8%a7%84%e8%8c%83%ef%bc%89/</link>
		<comments>http://www.xiaojiayi.com/2011/07/27/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b8%80%ef%bc%88%e5%9f%ba%e6%9c%ac%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e5%8f%8a%e5%91%bd%e5%90%8d%e8%a7%84%e8%8c%83%ef%bc%89/#comments</comments>
		<pubDate>Wed, 27 Jul 2011 03:16:17 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[symbian]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=126</guid>
		<description><![CDATA[本文内容非原创，属于网上资源的整理。 ======================================== 基本数据类型  在Symbian中，很多C++基本类型都被重新定义了，最好使用Symbian的，理由如下： 所有Symbian API都是用的Symbianc重定义的 将来Symbian OS由32位转为64位时，支持性更好 这本身就是Symbian C++ Coding Standards所要求的 1.  Integers     typedef signed int TInt;  C++中的signed int，32位，基本用法类似。     typedef unsigned int TUint;  一般用于计数器(Counter)或者标记(Flags)。     其他Int类型：TInt64， TInt32， TInt16，TInt8； 同时有一份TUint的版本。 2. Text  text类型在Symbian编程中基本不用，而一般采用描述符（descriptor）。TText默认是16位的。 3. Boolean      typedef int TBool;有两个枚举值：ETrue和EFalse。TBool变量最好不要直接和ETure和EFalse比较。如下： TBool flag = ETrue; if (flag)  // if (!flag) { flag = EFalse; [...]]]></description>
			<content:encoded><![CDATA[<p>本文内容非原创，属于网上资源的整理。</p>
<p>========================================</p>
<div align="left"><strong>基本数据类型</strong></div>
<div align="left"> 在Symbian中，很多C++基本类型都被重新定义了，最好使用Symbian的，理由如下：</div>
<ul type="disc">
<li>所有Symbian API都是用的Symbianc重定义的</li>
<li>将来Symbian OS<span style="color: #336699;">由32位转为64位时，支持性更好 </span></li>
<li>这本身就是Symbian C++ Coding Standards所要求的</li>
</ul>
<div align="left"><strong>1.  Integers</strong></div>
<div align="left">    typedef signed int TInt;  C++中的signed int，32位，基本用法类似。</div>
<div align="left">    typedef unsigned int TUint;  一般用于计数器(Counter)或者标记(Flags)。</div>
<div align="left">    其他Int类型：TInt64， TInt32， TInt16，TInt8； 同时有一份TUint的版本。</div>
<div align="left"><strong>2. Text</strong></div>
<div align="left"> text类型在Symbian编程<span style="color: #336699;">中基本不用，而一般</span>采用描述符（descriptor）。TText默认是16位的。</div>
<div align="left"><strong>3. Boolean </strong></div>
<div align="left">    typedef int TBool;有两个枚举值：ETrue和EFalse。TBool变量最好不要直接和ETure和EFalse比较。如下：</div>
<div align="left">TBool flag = ETrue;<br />
if (flag)  // if (!flag)<br />
{<br />
flag = EFalse;<br />
}</div>
<div align="left"><strong>4.  Floating Point</strong></div>
<div align="left">    对浮点数的支持视处理器而定，如果没有FPU，效率非常低，所以最好是不要用浮点数。如果一定要用，尽量转化为整数操作。<br />
typedef float TReal32;  typedef double TReal64; typedef double TReal;</div>
<div align="left"><strong>5. TAny</strong></div>
<div align="left">    typedef void TAny;</div>
<div align="left">    TAny一般只用作指针，其他情况下用void比较好。</div>
<div align="left">    TAny* MyFunction();     void MyOtherFn();</div>
<div align="left">    TAny* 在很多Symbian API中都用到了，如：</div>
<div align="left">    static TUint8* Copy( TAny* aTrg, const TAny* aSrc, TInt aLength);</div>
<div align="left"><strong>5. Enumerations</strong></div>
<div align="left">enum TState {EOff, Eon, EInit};</div>
<div align="left">Enumeration类型应该以T开头，而枚举值应该以E开头。</div>
<div align="left">TState  state = GetState();<br />
if (state == EOn)<br />
{<br />
//Do something here<br />
}</div>
<div align="left"><strong>命名规范</strong></div>
<div align="left">    <em>T类</em>：只包含值，而不包含指针以及外部的资源，在栈上分配空间。</div>
<div align="left">                TVersion osVersion = User::Version();</div>
<div align="left">    <em>C类</em>：所有需要分配内存的类都必须从CBase继承并且以C开头。</div>
<div align="left">class CExample : public CBase<br />
{<br />
private:<br />
CDesCArrayFlat* iArray;<br />
}</div>
<div align="left">CExample* example = new (ELeave) CExample;</div>
<div align="left">    <em>R类</em>：包含指向某个资源的handler。</div>
<div align="left">                RTimer timer;<br />
timer.CreateLocal();</div>
<div align="left">    <em>M类</em>：定义一个接口，一般只包含纯虚函数，不包含成员数据，减少类之间的依赖，用来接受回调消息。</div>
<div align="left">class MEikStatusPaneObserver<br />
{<br />
public:<br />
virtual void HandleStatusPaneSizeChange() = 0;<br />
}</div>
<div align="left">任何实现MEikStatusPaneObserver接口的类都必须实现HandleStatusPaneSizeChange()函数。</div>
<div align="left"><strong>1. 变量命名规范</strong></div>
<ul type="disc">
<li>    成员变量以“i”开头</li>
<li>    参数以“a”开头</li>
<li>    动态变量随便，以小写字母开头</li>
<li>    常量以“K”开头</li>
<li>    尽量不要使用全局变量，不能使用全局静态变量。</li>
</ul>
<div align="left"><strong>2. 函数命名规范</strong></div>
<ul type="disc">
<li>    函数以大写字母开头，如AddFileNameL();</li>
<li>    以D结尾表示deletion of an object</li>
<li>    以L结尾表示函数可能leave</li>
<li>    以C结尾表示一个item被放到cleanup stack</li>
</ul>
<div align="left"><strong>Casting</strong></div>
<div align="left">    Casting用于在类（classes）和类型（types）之间作转化，Symbian中仍然可以使用C中语法。</div>
<div align="left">    dynamic_cast：不支持，Symbian中没有RTTI。</div>
<div align="left">    static_cast：把一个基类转化为一个继承类。</div>
<div align="left">                   TInt intValue = 0xff;<br />
TUint8 byteValue = static_cast&lt;TUint8&gt;(intValue);</div>
<div align="left">    reinterpret_cast：把一个指针类型转化为另外一个指针类型，如integer转化为point类型或者相反。</div>
<div align="left">                   TUint32 fourBytes = 0;<br />
TUint8* bytePtr = reinterpret_cast&lt;TUint8*&gt; (&amp;fourBytes);<br />
bytePtr++;<br />
*bytePtr = 0xFF;</div>
<div align="left">    const_cast：移除一个类的const属性。</div>
<div align="left"></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2011/07/27/symbian%e5%ad%a6%e4%b9%a0%e7%ac%94%e8%ae%b0%e4%b8%80%ef%bc%88%e5%9f%ba%e6%9c%ac%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b%e5%8f%8a%e5%91%bd%e5%90%8d%e8%a7%84%e8%8c%83%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>生活在别处</title>
		<link>http://www.xiaojiayi.com/2011/07/14/%e7%94%9f%e6%b4%bb%e5%9c%a8%e5%88%ab%e5%a4%84/</link>
		<comments>http://www.xiaojiayi.com/2011/07/14/%e7%94%9f%e6%b4%bb%e5%9c%a8%e5%88%ab%e5%a4%84/#comments</comments>
		<pubDate>Thu, 14 Jul 2011 15:59:39 +0000</pubDate>
		<dc:creator>njuxjy</dc:creator>
				<category><![CDATA[生活]]></category>

		<guid isPermaLink="false">http://www.xiaojiayi.com/?p=117</guid>
		<description><![CDATA[来上海已经有一个多月了。 很早以前有个日本作家来上海“放荡形骸”了一番，回岛国后写了本叫《魔都》的书，记录了那段时间在上海的各种腐败体验。于是现在上海不情不愿地被冠以了“魔都”的称号。相对于魔都上海，我们还有帝都北京、妖都广州。我居住过的另一座城市南京也有个叫魔都的称号，所以一般称南京为小魔都，上海为大魔都。而无锡又不情不愿地被称为“小上海”，所以我从无锡滚到南京，再从南京滚到上海，就是从小小魔都滚到小魔都再滚到大魔都的过程。 网上流传着一篇很长的叫《魔都生存指南》的东西。作为一个标准吃货的作者，花了百分之四十的篇幅介绍了上海的公厕、语言、建筑、交通、气候、治安、休闲、购物等方面，剩下百分之六十的文字都用来介绍各种边边脚脚的腐败去处。作为一名偏居魔都东部小镇的IT民工兼吃货，只能含泪将网页收下，放入“以后再看”的文件夹中。有个地方我倒是天天可以经过，可以去试试： 魔都生存指南：张江地铁站美食点评特别篇&#8211;好吃的芝士蛋糕和面包“毂屋”其实真不需要多介绍了网上对他家的芝士蛋糕好评太多了，中午的意面或者三明治套餐也非常棒。特别推荐袋包装的野生酵母面包，发的不是很蓬松特别好吃，下班顺便带一袋回去吧 魔都生存指南：张江地铁站美食点评特别篇&#8211;地道的台湾小炒“龙门客栈”算是地铁站里比较精致的一家饭店了，比费尼阁要好吃不知道多少，基本上在张江中餐也就百草的味道可以和他比一比了，但是价格就划算大多了。我特别推荐一个菜单上没有的&#8211;九层塔菜圃蛋 我住的那地方和生存指南没什么关系。周围有跟你同样的一大群人，和你揣同样的梦想，同样的早起，去同一个包子铺买肉包，挤同一辆公车，盯着同一个漂亮姑娘看，脸上都写着牛逼或装逼，流同样多的汗，进满是IT民工的企业，对着同样尺寸的显示屏，吃同样价格的便当，加同样时间的班。偶尔会坐地铁去趟城里或回趟家，偶尔错过了最末班公车跟人拼车打的或坐小黑车，偶尔去小饭馆腐败下，偶尔自己买三两小菜小试牛刀。这里不需要什么生存指南，生活在这里，就好像是你站在原地不动，人群也会带着你去买包子挤公交上班，而你如果稍不留神的话，会发现，咦，自己又满身臭汗地回到家了。人群会指着你一路向南的。 说到生活，其实我想说“生活在拉稀，而我在便秘”。用这两个吸引眼球的词语无他意，只是想说生活节奏有点快，我有些不适应，思维有些阻塞。也许原来在南京懒散惯了，享受惯了上班只要走五分钟的轻松，可以打一天酱油毫无愧疚感的惬意。其实现在这样真是好事，要学游泳还是要去深水区学，在儿童区打打闹闹是学不会的。王朔的小说《橡皮人》描述过这样一群在都市生活的年轻人，他们如同工艺品，“被高高在上的观赏者轮流捏拿玩弄，被生活的泥匠用压力捏成各种形态”。我想我是不会成为橡皮人的，要做就做弹簧人。 如果每个人都是在自己的那条船上漂，如果那些点点滴滴的小事那些说过的云飞雪落不经意却记得的话是海上的风，那么一个人不属于平静的情绪便是由风吹起的浪花了。如果浪涛的拍打让坐船的你左右摇摆翻江倒海，如果你架起双桨劈风斩浪，如果你足够幸运很快迎来风平浪静，你拍拍胸脯骄傲地说，也就这样嘛。这时候你转过身发现，自己早就不在原来的地方，那些风和那些景一去不复返。然后你笑了，站在船头高唱“两岸猿声啼不住，轻舟已过万重山”。唱完，然后你泪流满面。 一个人一生到底会有百分之多少的时间花在路上。去学院自习室的路上，去厕所的路上，去汇杰广场的路上，去张江高科地铁站的路上，去喜欢的姑娘楼下的路上，去火车站北广场的路上，去玉兰四期家乐福买烤鸡的路上，去孟猪家蹭饭的路上，去茶水间泡杯饮料的路上，去超市买柠檬的路上，去邮局拿家里寄过来的被子的路上。知道了这个比例，我估计自己会蛋疼菊紧发誓珍惜时间云云。可是人活着并不是目的而是个过程，在路上也是属于这个过程的一部分，而不仅仅是为了达到一个目的。身体在赶路，脑子不一定要跟着赶路。 我想成为什么样的人。人傻，钱多，很多很多的钱。和人讨论PS3, iPhone, iPad, iMac, Wii, 蓝光，背投，机械鼠标，概念鼠标，GFW，宽带山。穿大裤衩人字拖，读GReader南方周末上推特，去哪都扛个iPad N代。征婚时介绍：人傻，钱多，速来。 毕业之前我想我会一个人出去旅行一次。要去就去远一点的地方，问谁借个单反装下样子，抓个破一点的包，要是iPad 2已经出了，买了塞包里，再塞两件衣服。多走路，多看，多拍，多吃。想想就来感。 没想到米兰昆德拉30多年前就帮我拟好了文章的题目。拿来一用，倒也切合现在的生活。现在是生活在别处，我希望将来能够变成生活在别墅。等到风景都看透，也许会最后回去看看细水长流。 　　胸中那可爱的洪水猛兽们，拿早点醒过来好伐啦~ 　　njuxjy@2010.08]]></description>
			<content:encoded><![CDATA[<p>来上海已经有一个多月了。</p>
<ol>
<li>很早以前有个日本作家来上海“放荡形骸”了一番，回岛国后写了本叫《魔都》的书，记录了那段时间在上海的各种腐败体验。于是现在上海不情不愿地被冠以了“魔都”的称号。相对于魔都上海，我们还有帝都北京、妖都广州。我居住过的另一座城市南京也有个叫魔都的称号，所以一般称南京为小魔都，上海为大魔都。而无锡又不情不愿地被称为“小上海”，所以我从无锡滚到南京，再从南京滚到上海，就是从小小魔都滚到小魔都再滚到大魔都的过程。<br /> 
<li>网上流传着一篇很长的叫《魔都生存指南》的东西。作为一个标准吃货的作者，花了百分之四十的篇幅介绍了上海的公厕、语言、建筑、交通、气候、治安、休闲、购物等方面，剩下百分之六十的文字都用来介绍各种边边脚脚的腐败去处。作为一名偏居魔都东部小镇的IT民工兼吃货，只能含泪将网页收下，放入“以后再看”的文件夹中。有个地方我倒是天天可以经过，可以去试试：<br />
<blockquote>
<p>魔都生存指南：张江地铁站美食点评特别篇&#8211;好吃的芝士蛋糕和面包“毂屋”其实真不需要多介绍了网上对他家的芝士蛋糕好评太多了，中午的意面或者三明治套餐也非常棒。特别推荐袋包装的野生酵母面包，发的不是很蓬松特别好吃，下班顺便带一袋回去吧
<p>魔都生存指南：张江地铁站美食点评特别篇&#8211;地道的台湾小炒“龙门客栈”算是地铁站里比较精致的一家饭店了，比费尼阁要好吃不知道多少，基本上在张江中餐也就百草的味道可以和他比一比了，但是价格就划算大多了。我特别推荐一个菜单上没有的&#8211;九层塔菜圃蛋</p>
</blockquote>
<li>我住的那地方和生存指南没什么关系。周围有跟你同样的一大群人，和你揣同样的梦想，同样的早起，去同一个包子铺买肉包，挤同一辆公车，盯着同一个漂亮姑娘看，脸上都写着牛逼或装逼，流同样多的汗，进满是IT民工的企业，对着同样尺寸的显示屏，吃同样价格的便当，加同样时间的班。偶尔会坐地铁去趟城里或回趟家，偶尔错过了最末班公车跟人拼车打的或坐小黑车，偶尔去小饭馆腐败下，偶尔自己买三两小菜小试牛刀。这里不需要什么生存指南，生活在这里，就好像是你站在原地不动，人群也会带着你去买包子挤公交上班，而你如果稍不留神的话，会发现，咦，自己又满身臭汗地回到家了。人群会指着你一路向南的。<br /> 
<li>说到生活，其实我想说“生活在拉稀，而我在便秘”。用这两个吸引眼球的词语无他意，只是想说生活节奏有点快，我有些不适应，思维有些阻塞。也许原来在南京懒散惯了，享受惯了上班只要走五分钟的轻松，可以打一天酱油毫无愧疚感的惬意。其实现在这样真是好事，要学游泳还是要去深水区学，在儿童区打打闹闹是学不会的。王朔的小说《橡皮人》描述过这样一群在都市生活的年轻人，他们如同工艺品，“被高高在上的观赏者轮流捏拿玩弄，被生活的泥匠用压力捏成各种形态”。我想我是不会成为橡皮人的，要做就做弹簧人。<br /> 
<li>如果每个人都是在自己的那条船上漂，如果那些点点滴滴的小事那些说过的云飞雪落不经意却记得的话是海上的风，那么一个人不属于平静的情绪便是由风吹起的浪花了。如果浪涛的拍打让坐船的你左右摇摆翻江倒海，如果你架起双桨劈风斩浪，如果你足够幸运很快迎来风平浪静，你拍拍胸脯骄傲地说，也就这样嘛。这时候你转过身发现，自己早就不在原来的地方，那些风和那些景一去不复返。然后你笑了，站在船头高唱“两岸猿声啼不住，轻舟已过万重山”。唱完，然后你泪流满面。<br /> 
<li>一个人一生到底会有百分之多少的时间花在路上。去学院自习室的路上，去厕所的路上，去汇杰广场的路上，去张江高科地铁站的路上，去喜欢的姑娘楼下的路上，去火车站北广场的路上，去玉兰四期家乐福买烤鸡的路上，去孟猪家蹭饭的路上，去茶水间泡杯饮料的路上，去超市买柠檬的路上，去邮局拿家里寄过来的被子的路上。知道了这个比例，我估计自己会蛋疼菊紧发誓珍惜时间云云。可是人活着并不是目的而是个过程，在路上也是属于这个过程的一部分，而不仅仅是为了达到一个目的。身体在赶路，脑子不一定要跟着赶路。<br /> 
<li>我想成为什么样的人。人傻，钱多，很多很多的钱。和人讨论PS3, iPhone, iPad, iMac, Wii, 蓝光，背投，机械鼠标，概念鼠标，GFW，宽带山。穿大裤衩人字拖，读GReader南方周末上推特，去哪都扛个iPad N代。征婚时介绍：人傻，钱多，速来。<br /> 
<li>毕业之前我想我会一个人出去旅行一次。要去就去远一点的地方，问谁借个单反装下样子，抓个破一点的包，要是iPad 2已经出了，买了塞包里，再塞两件衣服。多走路，多看，多拍，多吃。想想就来感。<br /> 
<li>没想到米兰昆德拉30多年前就帮我拟好了文章的题目。拿来一用，倒也切合现在的生活。现在是生活在别处，我希望将来能够变成生活在别墅。等到风景都看透，也许会最后回去看看细水长流。</li>
</ol>
<p>　　胸中那可爱的洪水猛兽们，拿早点醒过来好伐啦~</p>
<p>　　<a href="mailto:njuxjy@2010.08">njuxjy@2010.08</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.xiaojiayi.com/2011/07/14/%e7%94%9f%e6%b4%bb%e5%9c%a8%e5%88%ab%e5%a4%84/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

