存档

作者存档

objective-c 字符串拼接

2013年3月11日 没有评论

前几天需要用到字符串拼接的地方,突然短路了,不知道怎么写了。

在 java 和 c# 中,字符串的拼接是直接用 + 来操作的。在 OC 中,说是有下面3种方法,

  1. NSString *str=[NSString    initWithFormat:@”%@,%@” , a  , b];
  2. NSString *str=[a   stringByAppendingString: b];
  3. NSString *str=[string   stringByAppendingFormat:@”%@,%@”,  a  ,  b];

网上的说法是第二种方法效率更好一点,不过我就感觉不出来什么,具体情况具体对待好了。

分类: iOS, 一句话 标签:

奇闻一件

2013年2月6日 没有评论

上一篇日志我不是说票不好买的嘛,然后某一天又看到了了一个3号晚上的票,所以就提前走了。

虽然回家了,但是仍在处理一个事情,笑死我了。

3年前,某单位试水互联网,推出了一款基于互联网内容的软件。刚开始的时候,很受欢迎,加上自身的优势,用户增长的是越来越快了。在节前的时候,老板做了一个决定,也就是我们现在要处理的事情,就是把这个软件从用户电脑上给主动卸载掉。

这是我工作以来,遇到的最搞笑的事情,而且这样的事情居然发生在这样的一个单位。无论是做软件也好,还是做互联网应用也好,都是想着尽量地吸引用户,占领用户的电脑。老板决定通过各种技术的或者非技术的手段,想法设法地把已经出货的电脑上的软件给卸载掉,于是我在回家后仍然不得不测试如何完全卸载掉。

软件前后几个版本,功能也都有很多变更,对于一个软件来说,在已经出货到用户手里,要满足老板提出来的“只要用户联网了,就给干掉”要求,确属不容易。

我们将推出的更新包就一个功能,更新的时候卸载自身的主程序。对于曾经花了时间和精力在上面的我来说,很是心痛。然后让老板这么做的原因就在于一个潜在的可能的法律风险。不通过商务或者法务层面去解决,而直接的干掉,对于一个总监来说,感觉武断了些。总结经验教训,可能有以下几点:

1、不是亲生儿子不受重视。曾经的部门调整,让这个项目有点不受重视,虽然亲生儿子也凡善可陈。

2、老板没有互联网意识,还只是停留在软件层面。对于互联网的东西,不懂也不想学习。

3、不愿意承担任何风险。部门间的相互扯皮。

4、后期运营跟不上。用户上来了,但是高层不愿意投入资源来负责运营,做技术的干着急。每年的预算要的多,后来用都用不完,宁愿挥霍也不愿意投入。

 

事已至此,某单位第一次试水互联网应该以失败画上句号。

分类: 一句话 标签: ,

车票不好买哇

2013年1月20日 没有评论

 

今年一来是由于某些无下限浏览器的干扰把相对公平变得更不公平。另外由于某2货部门推广高铁,减少了直达的车次。

所以我就木有票拉。

本来夕发朝至的车,换成高铁后,价格多了200多,另外在转车的时间安排上变的不太合理了。我一直在犹豫要不要多出那200多块钱。口袋里的钱增长速度都跟不上物价的速度,连火车的更新换代速度都跟不上,真TM的惭愧。

分类: 一句话 标签:

c# 调用 c++ dll 问题的解决

2012年12月3日 没有评论

上一个星期,都在解决一个问题,c# 调用 c++ 的 dll 。

问题出现在字符串上,在 win8 64位+vs2012 环境下,64位的c#去调用64位的 c++ dll。在调试的时候,总是自动退出调试,没有进入异常,也没有什么输出。dll 方法是接收2个参数,并返回一个字符串。c# 通过调用获得返回的字符串。

一开始的时候,我以为是由于 c# 和 c++ 之间不同的类型转换时,我给设置错了类型导致,然后又仔细拿网上的好几篇文章做对比,发现这块没有问题。dll 文件并不是我们这边提供的,没有源码所以也不好联调。我就给 dll 那边发邮件,描述情况,并期待他们的反馈。

对方那边就只会c++,我提供的c#代码他们看不太懂,再加上对方没有64位环境,同时也不愿意提供dll的源码给我这边调试,进度比较慢。白天就是邮件来邮件去,晚上的时候我就各种安装系统,发现这问题只在64 位系统上出现,在 32 位系统上是可以正确调用的。

后来突然想到,如果我这边新建一个 c++ 项目的话,能不能够复现呢?果然,问题复现了,现在抛开对方的 dll 文件,也可以进行调试了。经过跟踪,发现 c++ 代码完全成功执行了,但是在 c# 调用这边就崩溃了。这么看起来,似乎和 c++ 代码方面的关系不大。于是又仔细检查了 c++ 的导出函数设置,没有问题。我以为是我c#项目的问题,删掉重建了个简单的,还是不行。

接下来,我又怀疑是不是 vs 本身的问题,因为是用的 2012 的版本,恰好这个时候,vs2012 sp1补丁包出来了,果断地升级。升级后发现还是崩溃了。

到这里似乎没有进展了,最后我请教了 c++ 方面的救兵。雪飞同学果然很是强悍,不多会就给出了我一个解决方法。在 c# 这边的函数申明这里设置返回类型为 IntPtr 类型,然后使用 Marshal.PtrToStringAuto 方法进行转换为托管字符串。问题就解决了。

我们一起还讨论这个问题出现的原因,一个可能的原因是在64位平台上,c++ 返回的是一个64位的指针,但是c#在调用的时候,并没有作为64位指针来获取,或者说拿了一个错误的指针,导致字符串获取失败。有可能在 c# 64位平台上字符串的初始化的时候,从非托管代码到托管代码的构造函数里存在缺陷。当然这个问题,是不是这样的,我们就不清楚了。获取给 vs 的开发team发个邮件可以得到更详细的信息。

在今天的时候,我越想越愤懑,为什么别的语言可以,c# 就非得这样,在32位和64位平台上还要做区分代码编写。碰巧下午我测试时先申明了字符串,然后再调用,发现问题居然解决了。似乎验证了和雪飞同学一起讨论的结果。

可是,最好的一个解决方法居然是这样的。这一刻,我觉得太蛋疼了。真的。

string s=””;s=GetInfo(); 的写法和 string s=GetInfo(); 之间对于托管代码和非托管代码居然有这样的区别。

 

还有另外一个问题,就是结构体转换成字节时,进入了异常。也是字符串的问题,后来根据 google 上面的搜索解决了。如果结构体里包含字符数组,在转换成字节时,需要先定义长度,不然会转换失败。具体来说就是在结构体里字符数组前面添加属性定义。例如

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 6)]             public char[] device ;  //这里的 device 为 “iphone”,长度为6,所以 SizeConst=6

 

分类: 日常 标签: , , , , ,

Apple 个人开发者帐号注册申请

2012年11月19日 没有评论

前面的文章中,我讲述了如何注册申请微软开发者帐号的大致流程。在这里,再来描述下苹果个人开发者帐号的注册申请好了。

我在申请前,都有看过网上的教程和帖子。比较坑爹的是,我看到的几乎所有的全部都是讲的企业开发者帐号的申请,看来都只有企业才有钱去搞 iOS 的开发哇。彼时我都蛋疼乳酸的不得了,所以把自己申请的过程讲一下,希望对大家有帮助。

在使用水果的设备时,需要一个帐号来进行程序的管理。这个帐号就是 Apple ID,其实微软的 Microsoft ID 就是学的水果的,还有什么 Adobe ID, Lenovo ID 啊诸如此类的。进行常规注册就可以了,这对于大家来说都是轻车熟路了。

以手机为例,进入到水果的手机开发者中心,https://developer.apple.com/devcenter/ios/index.action 登陆后申请。输入个人信息、支付信息什么的。在这里需要特别注意的是 Legal Name 这个文本框里就是将来在 store 里显示是组织名称,可惜我是随便填写的,悲催了。各位同学这里可是要慎重取个好名字哈。

填写完成后,水果会给你一个 pdf 的表格,按照要求,是需要打印然后填写,最后传真给水果。这对于个人开发者来说,还是太挑剔了点,好在我从网上找到了可以免费发传真的地方。把 pdf 用ps 打开,该勾选的勾选,签名那里用画笔工具尽量模仿自己的手写,然后通过免费传真发送过去了。本来还担心水果会不会拒绝,最后没有想到还通过了。

不过这个等待的过程就太长了些,前后差不多等待了近一个星期的样子,这对于急性子的我来说近乎是种煎熬。终于在某一天的早上,收到了含有激活码的邮件,可是验证的时候,就无法激活。显示的是一堆的英文字母,看也看不懂,只好在线给他们求助,好在当天就回复了。邮件也是英文的,看不懂,貌似大意就是说让再重新激活下。于是重新激活,就成功了。

晚上回家后,尝试进行真机调试,也无法调试。发现工程属性里的版本不对,手机是 ios 6 ,但是工程里的是 ios 5,修改后还是不行。后来无意间发现,在真机的设备页里,点击那个“作为开发使用”的按钮后,才可以真机调试了。

大家还记得我前文中,提到的那个 MMHot 应用么,我安装到真机上,感觉福利图好爽的样子喔。

分类: iOS, 日常 标签: , ,

windows 8 个人开发者帐号注册申请

2012年11月19日 没有评论

win8 在上个月的时候终于开始发售了,作为开发者,自然很关心新出来的应用商店开发的事情了。

在先前的时候,开发者帐号只针对于企业用户和有邀请码的个人用户。普通用户是申请不到的。现在普通用户终于也可以申请拉。

通过 vs 2012 的起始页或者干脆网页访问 http://msdn.microsoft.com/zh-cn/windows/apps/br229512 ,可以进入到微软开发中心的页面进行帐号的注册和申请。

注册流程很简单,事实上,你在安装 win8 的时候,系统就会提示你是否要注册一个帐号。该帐号和我们这里要注册的帐号其实是同一个概念,Microsoft ID 。需要提醒大家的是,信息里的个人邮箱和手机号码一定要填写真实的喔,在后面的流程里会经常地用到的。例如手机接收验证码,邮箱收取支付信息。

对于个人用户,一年的费用是300人民币,如果是学生的话,符合条件的可以减免第一年的费用,也就是说第一年不要钱的。我都离开学校好几个世纪了,还是老实地交钱吧。这里需要注意的是在用信用卡支付的时候,需要选择支持境外支付的卡片。

支付成功后,就可以进入到后台到处看一看拉。不过这个时候,还不能上传应用,需要一个二次确认。在这个时候,微软会对信用卡再一次扣费,扣费金额大小不等。在第二次扣费的对账单里,会有几个数字。二次确认就是需要你输入对账单里的数字,或者扣费的具体金额。通过了二次确认后,才是真正地可以上传程序了。

当然,第二次扣费,微软会再返回给我们的。

win8 使用的几个小提示

2012年11月1日 没有评论

昨天头脑发热,从vs 里进去花了 300 块买了一个微软开发者帐号,然后晚上的时候又花了 98 块钱弄了个 win 8 的升级 key 。如果有兴趣的同学也想只花 98 块钱升级的话可以和我联系获取详细的攻略咯,支持一下正版。

大半夜的开始安装 win 8 镜像,先前通过工作的便利制作了 win 8 的启动U盘,安装过程倒是轻车熟路的。进入了系统后,发现  store 应用商店无法打开。其实这个问题以前也碰到过,再安装一次就可以。半夜的时候再重装就够呛了,想从网上搜一搜解决的方法,结果网上的内容很少,说什么修改 dns 解析为 8.8.8.8 啊,修改注册表啊什么的,看起来都不是好方法。

根据网上的资料不断地摸索,终于发现了问题的解决方法了。就是把当前的网络共享给关闭了就可以了。应用商店让人耳目一新,比先前内测时候的多了很多东西。QQ 、新浪微博、人人网这些应用也都是从内测一路走过来的,他们确实是修正了不少的bug,赞一个。

win 8 要使用应用商店的话,就必须有一个 Microsoft ID,但是我又很想用以前的 Administrator 账户怎么办呢,其实通过组策略也可以实现的。

虽然禁用了UAC,但是程序图标上的那个盾牌怎么都不消失,看着真别扭。这个目前还没有找到很好的解决思路。

昨天晚上没有睡好,现在好瞌睡啊。

分类: 一句话, 日常 标签: ,

xcode 调试查找 EXC_BAD_ACCESS 问题根源

2012年10月22日 没有评论

这几天在调试当初的一个demo的程序的时候,一运行就报错,本来就对 xcode 不熟悉,这下更是手忙脚乱的。貌似这里面的断点调试也不怎么好用,放了几个断点,然后逐步执行。

运行到最后,出错的时候是停留在表格的显示的方法里,但是感觉不对。很是郁闷,这个和vs 比起来要弱爆了。看了下异常信息,提示的是 EXC_BAD_ACCESS 错误。在网上搜索了下,还很多人都有这个错误呢。

总计了下大家的建议,说的是 90% 的EXC_BAD_ACCESS 异常都是因为释放了已经释放的变量导致。安装网上的说法要打开 NSZombieEnabled 来显示更多的信息。

我这里说一个简单的方式:Product->Edit Scheme,然后选择 Diagnostics 选项卡,勾选 Enable Zombie Objects ,然后再重新调试,就可以显示一些更有用的信息了。再 Output 里显示了 UIAlertView 的字符串,我的项目里用到了这个,但是不太多,一搜索果然发现和定位了错误。

我在一处声明了 UIAlertView 并且使用了 autorelease 关键字,但是在后面,我又 release 了一遍,导致出错了。最开始学习的时候,我是从网上照葫芦画瓢地写的这样的代码。

修正了错误后,重新编译就没有问题了。心里的石头算是放下来了。网上的文章还有继续讲解如何来来进行定位操作的,我看了下还需要执行命令,这对我来说复杂了,问题本来也解决了,就没有继续跟了。有兴趣的同学可以搜索网上相关的文章看看。

最后需要提醒大家的,再找到了错误原因后,需要重新取消勾选 Enable Zobie Objects 复选框。

分类: iOS, 一句话 标签: ,

iOS 预定义声音参考表

2012年10月19日 没有评论

在上一个应用 MMHot 中,我们讲解了如何显示图片,后来我打算再添加一个功能,就是长按屏幕可以保存图片,保存图片后播放一个声音通知用户。声音的播放使用了 AudioServices。

AudioServices 是 Audio Toolbox 下的一个播放小于 30秒 声音的功能集合。从 ios 2.0 开始,在系统中欲定义了一些系统声音,它们从 1000 到 2000。内置的声音文件存放的地址为 /System/Library/Audio/UIsounds/ 。

Sound ID File name (iPhone) File name (iPod Touch) Category Note
1011 SMSReceived_Vibrate
1102 FailedUnlock
1311 SMSReceived_Vibrate
1350 RingerVibeChanged
1351 SilentVibeChanged
4095 Vibrate There was no category for this sound before 2.2. In the SDK this is the constant kSystemSoundID_Vibrate.
1005 alarm.caf sq_alarm.caf CalendarAlert
1304 alarm.caf sq_alarm.caf SystemSoundPreview
1020 Anticipate.caf Anticipate.caf SMSReceived_Alert Available since 4.2
1320 Anticipate.caf Anticipate.caf SMSReceived_Selection Available since 4.2
1106 beep-beep.caf sq_beep-beep.caf ConnectedToPower
1113 begin_record.caf begin_record.caf BeginRecording Available since 3.0
1117 begin_video_record.caf begin_video_record.caf BeginVideoRecording Available since 3.0
1021 Bloom.caf Bloom.caf SMSReceived_Alert Available since 4.2
1321 Bloom.caf Bloom.caf SMSReceived_Selection Available since 4.2
1022 Calypso.caf Calypso.caf SMSReceived_Alert Available since 4.2
1322 Calypso.caf Calypso.caf SMSReceived_Selection Available since 4.2
1023 Choo_Choo.caf Choo_Choo.caf SMSReceived_Alert Available since 4.2
1323 Choo_Choo.caf Choo_Choo.caf SMSReceived_Selection Available since 4.2
1070 ct-busy.caf ct-busy.caf AudioToneBusy There was no category for this sound before 4.0.
1074 ct-call-waiting.caf ct-call-waiting.caf AudioToneCallWaiting There was no category for this sound before 4.0.
1153 ct-call-waiting.caf ct-call-waiting.caf VCCallWaiting Available since 4.1
1071 ct-congestion.caf ct-congestion.caf AudioToneCongestion There was no category for this sound before 4.0.
1073 ct-error.caf ct-error.caf AudioToneError There was no category for this sound before 4.0.
1075 ct-keytone2.caf ct-keytone2.caf AudioToneKey2 There was no category for this sound before 4.0.
1072 ct-path-ack.caf ct-path-ack.caf AudioTonePathAcknowledge There was no category for this sound before 4.0.
1024 Descent.caf Descent.caf SMSReceived_Alert Available since 4.2
1324 Descent.caf Descent.caf SMSReceived_Selection Available since 4.2
1200 dtmf-0.caf dtmf-0.caf TouchTone
1201 dtmf-1.caf dtmf-1.caf TouchTone
1202 dtmf-2.caf dtmf-2.caf TouchTone
1203 dtmf-3.caf dtmf-3.caf TouchTone
1204 dtmf-4.caf dtmf-4.caf TouchTone
1205 dtmf-5.caf dtmf-5.caf TouchTone
1206 dtmf-6.caf dtmf-6.caf TouchTone
1207 dtmf-7.caf dtmf-7.caf TouchTone
1208 dtmf-8.caf dtmf-8.caf TouchTone
1209 dtmf-9.caf dtmf-9.caf TouchTone
1211 dtmf-pound.caf dtmf-pound.caf TouchTone
1210 dtmf-star.caf dtmf-star.caf TouchTone
1114 end_record.caf end_record.caf EndRecording Available since 3.0
1118 end_video_record.caf end_video_record.caf EndVideoRecording Available since 3.0
1025 Fanfare.caf Fanfare.caf SMSReceived_Alert Available since 4.2
1325 Fanfare.caf Fanfare.caf SMSReceived_Selection Available since 4.2
1115 jbl_ambiguous.caf jbl_ambiguous.caf JBL_Ambiguous Available since 3.0
1110 jbl_begin.caf jbl_begin.caf JBL_Begin Available since 3.0
1112 jbl_cancel.caf jbl_cancel.caf JBL_Cancel Available since 3.0
1111 jbl_confirm.caf jbl_confirm.caf JBL_Confirm Available since 3.0
1116 jbl_no_match.caf jbl_no_match.caf JBL_NoMatch Available since 3.0
1026 Ladder.caf Ladder.caf SMSReceived_Alert Available since 4.2
1326 Ladder.caf Ladder.caf SMSReceived_Selection Available since 4.2
1100 lock.caf sq_lock.caf ScreenLocked
1305 lock.caf sq_lock.caf SystemSoundPreview
1254 long_low_short_high.caf long_low_short_high.caf Headset_StartCall
1006 low_power.caf low_power.caf LowPower
1001 mail-sent.caf mail-sent.caf MailSent
1303 mail-sent.caf mail-sent.caf SystemSoundPreview
1259 middle_9_short_double_low.caf middle_9_short_double_low.caf Headset_TransitionEnd
1027 Minuet.caf Minuet.caf SMSReceived_Alert Available since 4.2
1327 Minuet.caf Minuet.caf SMSReceived_Selection Available since 4.2
1000 new-mail.caf new-mail.caf MailReceived
1302 new-mail.caf new-mail.caf SystemSoundPreview
1028 News_Flash.caf News_Flash.caf SMSReceived_Alert Available since 4.2
1328 News_Flash.caf News_Flash.caf SMSReceived_Selection Available since 4.2
1029 Noir.caf Noir.caf SMSReceived_Alert Available since 4.2
1329 Noir.caf Noir.caf SMSReceived_Selection Available since 4.2
1108 photoShutter.caf photoShutter.caf CameraShutter
1003 ReceivedMessage.caf ReceivedMessage.caf SMSReceived
1301 ReceivedMessage.caf ReceivedMessage.caf SystemSoundPreview
1107 RingerChanged.caf RingerChanged.caf RingerSwitchIndication
1004 SentMessage.caf SentMessage.caf SMSSent
1109 shake.caf shake.caf ShakeToShuffle Available since 3.0
1030 Sherwood_Forest.caf Sherwood_Forest.caf SMSReceived_Alert Available since 4.2
1330 Sherwood_Forest.caf Sherwood_Forest.caf SMSReceived_Selection Available since 4.2
1255 short_double_high.caf short_double_high.caf Headset_Redial
1257 short_double_low.caf short_double_low.caf Headset_EndCall
1258 short_double_low.caf short_double_low.caf Headset_CallWaitingActions
1256 short_low_high.caf short_low_high.caf Headset_AnswerCall
1051 SIMToolkitCallDropped.caf SIMToolkitCallDropped.caf SIMToolkitTone
1052 SIMToolkitGeneralBeep.caf SIMToolkitGeneralBeep.caf SIMToolkitTone
1053 SIMToolkitNegativeACK.caf SIMToolkitNegativeACK.caf SIMToolkitTone
1054 SIMToolkitPositiveACK.caf SIMToolkitPositiveACK.caf SIMToolkitTone
1055 SIMToolkitSMS.caf SIMToolkitSMS.caf SIMToolkitTone
1007 sms-received1.caf sms-received1.caf SMSReceived_Alert
1012 sms-received1.caf sms-received1.caf SMSReceived_Alert
1307 sms-received1.caf sms-received1.caf SMSReceived_Selection
1312 sms-received1.caf sms-received1.caf SMSReceived_Selection
1008 sms-received2.caf sms-received2.caf SMSReceived_Alert
1308 sms-received2.caf sms-received2.caf SMSReceived_Selection
1009 sms-received3.caf sms-received3.caf SMSReceived_Alert
1309 sms-received3.caf sms-received3.caf SMSReceived_Selection
1010 sms-received4.caf sms-received4.caf SMSReceived_Alert
1310 sms-received4.caf sms-received4.caf SMSReceived_Selection
1013 sms-received5.caf sms-received5.caf SMSReceived_Alert
1313 sms-received5.caf sms-received5.caf SMSReceived_Selection
1014 sms-received6.caf sms-received6.caf SMSReceived_Alert
1314 sms-received6.caf sms-received6.caf SMSReceived_Selection
1031 Spell.caf Spell.caf SMSReceived_Alert Available since 4.2
1331 Spell.caf Spell.caf SMSReceived_Selection Available since 4.2
1032 Suspense.caf Suspense.caf SMSReceived_Alert Available since 4.2
1332 Suspense.caf Suspense.caf SMSReceived_Selection Available since 4.2
1033 Telegraph.caf Telegraph.caf SMSReceived_Alert Available since 4.2
1333 Telegraph.caf Telegraph.caf SMSReceived_Selection Available since 4.2
1057 Tink.caf Tink.caf PINKeyPressed
1103 Tink.caf sq_tock.caf KeyPressed
1034 Tiptoes.caf Tiptoes.caf SMSReceived_Alert Available since 4.2
1334 Tiptoes.caf Tiptoes.caf SMSReceived_Selection Available since 4.2
1104 Tock.caf sq_tock.caf KeyPressed
1105 Tock.caf sq_tock.caf KeyPressed
1306 Tock.caf sq_tock.caf KeyPressClickPreview The category was SystemSoundPreview before 3.2.
1016 tweet_sent.caf tweet_sent.caf SMSSent Available since 5.0
1035 Typewriters.caf Typewriters.caf SMSReceived_Alert Available since 4.2
1335 Typewriters.caf Typewriters.caf SMSReceived_Selection Available since 4.2
1101 unlock.caf sq_lock.caf ScreenUnlocked
1036 Update.caf Update.caf SMSReceived_Alert Available since 4.2
1336 Update.caf Update.caf SMSReceived_Selection Available since 4.2
1050 ussd.caf ussd.caf USSDAlert
1152 vc~ended.caf vc~ended.caf VCEnded Available since 4.0
1150 vc~invitation-accepted.caf vc~invitation-accepted.caf VCInvitationAccepted Available since 4.0
1151 vc~ringing.caf vc~ringing.caf VCRinging Available since 4.0
1154 vc~ringing.caf vc~ringing.caf VCCallUpgrade Available since 4.1
1002 Voicemail.caf Voicemail.caf VoicemailReceived
1015 Voicemail.caf Voicemail.caf Available since 2.1
1300 Voicemail.caf Voicemail.caf SystemSoundPreview
1315 Voicemail.caf Voicemail.caf SystemSoundPreview Available since 2.1

使用的时候,添加引用 #import <AudioToolbox/AudioToolbox.h>

SystemSound sound=1109;
AudioServicesPlaySystemSound(sound);

播放是以当前系统的音量来进行后台播放,比较适合我在这个应用中的需要。

分类: iOS, 转载 标签: , ,

MMHot 代码编写过程及心得

2012年10月17日 没有评论

把先前买的那本 ios 变成的书给撕了,每天在地铁上看一点点,又大致看了几个别人的代码,打算自己写一个应用出来练习下,经过一个星期的琢磨,应用 MMHot 代码部分终于完工了。本来打算花 $99 去买一个开发者帐号的,但是昨天晚上看了下水果的应用商店规范,发现 MMHot 应该不会被审核通过的,于是放弃了。$99 对我来说真心贵,不过这个不妨碍今天和大家一起分享这个应用编写的心得。

简单地说,MMHot 是一个浏览美女图片的 ios 应用。

项目使用了 2 个开源的库:EGOImage 和 ASIHttp,所以我觉得这个作为入口比较适合新手来初步了解和学习 objective-c ,既可以完成任务,又在学习的初期降低了门槛。ASIHttp  封装了网络应用中的大部分功能,可以满足常见的 get/post 例如文件下载、上传。EGOImageView 继承了 UIImageView,支持图片的异步下载。

作业的目标:1、大致了解 EGOImage 和 ASIHttp 的简单使用方法。2、代码添加视图。3、学习使用调试,了解 IDE 的功能。

应用是基于 Xcode 4.5.1 和 iOS 6 。新建项目时,我没有选择 Core Data 和 Automatic Reference Counting 。因为我看的代码都是基于用户自己手动管理内存的方式,ARC 跳跃太大,对我不合适。另外的原因是开源的库当前貌似还不支持ARC。

新建项目后,会自动包含 appDelegate 文件。这块需要注意的是 -(void)application:(UIApplication *) application didFinishLaunchingWithOptions:(NSDictionary *) launchOptions 方法。这个方法里用来设置需要第一个显示的视图。我们在很多应用中都看到当应用第一次运行的时候,会给出引导界面让用户了解大致的流程,第二次运行时就不显示引导界面了,为了实现这样的效果,也可以在这个方法里去实现。

在该方法里,包含下面的语句:

self.window=[[[UIWindow alloc] initWithFram:[[UIScreen mainScreen] bounds]] autorelease];
self.viewController=[[[MainViewController alloc] initWithNibName:@”MainViewController” bundle:nil] autorelease];
self.window.rootViewController=self.viewController;
[self.window makeKeyAndVisible];
return YES;
第一行代码是设置界面的window,由 IDE 自动生成,第二行代码是设置程序显示的第一个界面 MainViewController.xib ,第三回是设置窗体的根视图,对于 ios6 系统,要求每个窗体都必须有根视图。由旧系统转换的时候,如果没有添加的话,IDE 也会给出一个警告。第四、五也是自动生成的,很明了。

接下来,我们转到 MainViewController.h 文件。由于我们使用了前面说的2个开源库,所以需要引用进来。另外,由于应用中使用了手势和图片回调,所以还需要添加对应的 delegate:EGOImageViewDelegate 、UIGestureRecognizerDelegate 。该类有 3个变量和一个属性。

EGOImageView *imageView;
ASIHttpRequest *req;
NSMutableArray *list

@property (nonatomic,retain) EGOImageView *imageView;

然后就是具体的实现了。我们在 viewDidLoad 添加初始化代码,图片浏览嘛,当然要把顶部的任务栏给隐藏掉,所以我首先来隐藏任务栏:[[UIApplication sharedApplication] setStatusBarHidden:YES];

UIImage *image=[UIImage imageNamed:@”1.jpg”];
imageView=[[EGOImageView alloc]initWithImage:image];
[imageView setFrame:CGRectMake(0,0,[UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)];
imageView.delegate=self;
[self.view.assSubview:imageView];

//添加手势识别
UISwipGestureRecognizer *swipLeft=[[UISwipGestureRecognizer alloc] initWithtarget:self action:@selector(handleSwipGesture:)];
swipLeft.direction=UISwipGuestureRecognizerDirectionLeft;
[self.view addGuestureRecognizer:swipLeft]; //为了防止图片旋转后,手势也跟随变化,所以把手势添加到根视图中,而非 imageView
[swipLeft release];

//发送请求
req=[ASIHttpRequest requestWithURL:[NSURL URLWithString:@”http://www.withonly.com”]];
[req setDelegate:self];
[req setDidFinishSelector:@selector(ASIHttpRequestFinished:)];
[req setDidFailSelector:@selector(ASIHtppRequestFailed:)];
[req startAsynchronous];

视图在显示的时候,首先显示一个本地图片文件 1.jpg ,这样的话可以避免网络延迟带来的视觉等待,然后将视图添加到窗体视图中。手势识别没有什么好说的,都一样。最后是发送请求,请求成功时执行ASIHttpRequestFinished,失败时执行ASIHtppRequestFailed。需要提醒大家的是第 4 行,我3天晚上没有睡好觉就是因为少了这一行代码。

-(void) ASIHttpRequestFinished:(ASIHttpRequest *) request{
NSString *info=[request responseString];
NSMutableString *str=[[NSMutalbeString stringWithString:info];
NSError *error;
NSRegularExpression *regex=[NSRegularExpression regularExpressionWithPattern:@”img src=\”(.*?)\”” options:NSRegularExpressionCaseInsensitive| NSRegularExpressionDotMatchesLineSeparators error:&error];
NSArray *matches=[regex matchesInString:str options:NSMatchingCompleted range:NSMakeRange(0,[str length])];
if([matches count]>0){
[list removeAllObjects];
}

for(NSTextCheckingResult *match in matches){
NSRange range=[match rangeAtIndex:1];
[list addObject:[str substringWithRange:range]];
}
if([list count]>0){
[imageView setImageURL:[NSURL URLWithString:[list objectAtIndex:0]]];
[self ResizeImage]; //图片缩放
}

}

当请求成功后,通过正则提取返回结果里的图片 url 地址,并且保存在 list 变量里。最开始的时候是打算使用xml 来解析的。可是网上搜索了下2种关于xml解析的思路,和 java 是一个味道,擦的,难道没有net 风格的么。于是换做正则来提取。解析完了后,如果 list 里有记录,则显示第一条记录里放的图片。其它的方法都差不多了,没有啥好说的。

在文章的最后,我说一说那个让我好几天没有睡好觉的问题。因为在加载图片后,还需要对图片进行缩放。但是由于图片的下载过程是一个异步的操作,最开始的缩放代码里总是会崩溃,因为那时图片都没有下载回来。我很期待有一个类似图片加载完的回调方法。

后来,查看了EGOImageView 的源文件,发现里面有 imageViewLoadedImage 方法,然后添加到文件里,发现没有效果,后来又发现了imageButtonLoadedImage ,添加进去还是没有效果。很崩溃,于是在网上看到有用 NSNotification  来解决的。赶紧添加进去,还是不行。弄了几个晚上都没有有效的方法。

最后才发现,其实 EGOImageView 已经内部实现了 NSNotification 的相关方法了,只需要在代码里添加 imageView.delegate=self ,然后在 imageViewLoadedImage 实现回调例如图片的缩放就可以了。

分类: iOS, 日常 标签: , , , ,