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, 日常 标签: , , , ,

loaded the “ViewControl” nib but the view outlet was not set 错误的解决办法

2012年10月10日 没有评论

糗事的 ios 项目最近一直都无法编译运行,因为每次 command+R 的时候都出现了 loaded the “ViewControl” nib but the view outlet was not set  这个错误提示。本来英语就不咋滴,再加上对 xcode 和 objective-c 不熟悉,简直弄昏了头。

后来发现了解决方法,很简单,基本功的问题。

1、先点击 File’s Owner ,然后选择右边的 Identity inspector 选项卡,Custom Class 窗口,Class 文本框里输入 xib 文件的文件名,这里是 ViewControl ,回车。

2、在 File’s Owner 里添加一个 Outlet 到 view 控件。具体方法见上一篇文章

3、重新编译,就可以运行了。

 

原因分析:由于当初新建项目时默认的 View 控件被我给删除了,后来我又添加的一个 view 控件。和新建项目默认的view不一样的地方在于,File’s Owner 的 Class 默认为 NSObject ,所以需要手工修改和当前的nib文件关联。

感觉在学习多视图处理的时候如果不注意应该也会碰到这个问题吧。

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

Xcode 中插座变量和动作释疑

2012年10月10日 没有评论

几乎在一年前,我的博客里《iOS版本的hello world》是发表的第一篇关于 ios 开发的文章,那只是一个很简单的示例,之后我就在没有再写了。一来是因为我很懒,另外一个很重要的原因就是我被一个问题弄迷惑了。

一年前,我从网上下了几个电子书,晚上躲在被窝里慢慢看。你知道的,现在我几乎很少买书的,这方面的书都太贵了,到后来才买的一本书。正是这书里的内容让我迷惑了很久很久。在  cocoaChina 上看了下,感觉有点高级不太针对入门的人,朋友中也没有人可以问,所以一直在困惑。

我们来举一个例子来说明下,在视图中有一个文本框和一个按钮,点击按钮显示文本框里的内容。要如何实现呢?

1、在 h 文件里添加一个属性,代码为 @property (nonatomic,retain) IBOutlet UITextView *txtInfo;

2、在 h 文件里添加一个动作 -(IBAction) btnClick:(id) sender;

3、在m文件里写实现代码 @synthesize txtInfo;  -(IBAction)btnClick:(id)sender{//这里是具体的点击实现按钮}

在这个时候来运行程序的话,应该是得不到预期的效果,为什么呢?因为还没有把控件和代码变量绑定起来。

接下来是第4步,4、切换到 xib 文件,拖动 File’s Owner 到文本框上去;然后拖动按钮到 File’s Owner 上去。需要注意的是,他们的拖动方向相反,前后并不一致。此时编译运行程序,应该就可以得到预期效果了。

其实第4步操作就是标题所述的绑定插座变量和动作。这个时候,我的疑问就来了。为什么要拖动方向相反呢,我要如何记住拖动的方向呢?

我就一直在纠结,为什么 xcode 不能像 vs 那样友好一些,拖下控件就可以写代码多好呀。

只到上个周末,我突然就明白了,那本书坑爹呀。

第4步是可以用一个方向来完成的,在 File’s Owner 上面点击右键,会弹出菜单。将里面的 + 号拉到控件上去一样第可以实现目的。插座变量,动作都可以用相同的顺序来。其实在 .net 里,是vs帮我们完成了这个绑定的操作。例如:

protected Button btn;  btn.Click+=new btn_Click;  protected void btn_Click(object sender, EventArgs e){}

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

vs 2012 中js的intellisense智能提示

2012年9月17日 没有评论

在前面的博客里提及 Visual Studio 2012 RTM 已经出来有一段时间了,在 vs 以前的版本里,对于用户的智能提示做的还不够好,在 2012 的版本里大有改善,今天我们要分享的是如何在  vs 2012 里使用用户 js 的 intellisense 智能提示。

使用起来还是很简单的,比如说项目中有个 common.js 文件,这个时候只需要添加一个名为  common.intellisense.js 的文件就可以了。IDE 可以自动发现,在开始的时候我还不清楚,专门在页面里引用了下,结果运行时总报告错误,后来才发现这个技巧。

场景:在common.js 文件里有一个 load 方法,有2个参数 ,格式如下:

function load(url,charset){}

要实现 intellisense 智能提示,我们只需要在 common.intellisense.js 文件里添加下面的方法即可:

intellisense.annotate(window,{     “load”:function(){
/// <signature>
///   <summary>加载 js 文件</summary>
///   <param name=”url” type=”String”>js 文件的路径</param>
///   <param name=”charset” type=”String”>js 文件的字符编码,例如 utf-8</param>
///   <returns type=”Object” />
/// </signature> }, });

简单地说,我们只需要完善 intellisense.annotate 方法即可,该方法接受 2 个参数,第一个参数为想要进行智能提示的对象,示例中使用的是 window 对象,也可以是其它的对象;第二个参数是一个 json 对象,传递的是智能提示的参数列表。

智能提示以 signature 包含,常见的有 3个,summary 描述的是该方法的功能;param 是具体每一个参数的描述,还可以包括类型;return 是返回类型的描述。从事 C#/asp.net 、Java 的同学看着是不是觉得很熟悉呀~

此时,我们在页面中输入 load 时,就会出现描述的内容,输入参数时,就会提示参数相关的信息,感觉太酷了。

如果我们在文件头添加 reference 引用,就可以脱离上文中 js 代码必须和智能提示文件文件名对应的限制了,例如 /// <reference path=”Scripts/jquery-1.7.1-intellisense.js”/> 。如果你愿意,可以同时引入多个 reference 文件,需要提醒各位的是这里的斜杠可是 3 个哟,不要输入错了。

看起来很简单,对不对。如果有什么问题,快给我留言吧。

在Webform (asp.net)中使用Route 路由之中级实现

2012年9月7日 没有评论

相信经过前面2节文字的介绍,同学们可以快速地实现route路由的目的,并运用在实际的项目中了。在这一节里,我们在讲述一下路由更进一步的实现。

在前面的例子里,我们是把所有的路由信息给放在 Globla.asax.cs 文件里了,这样就产生了一个问题:由于实际业务的变化,每次都需要在该文件里做调整,然后重新编译部署。是不是觉得很麻烦,有没有一种更好的方式,不需要编译是最好啦。

很自然,有经验的同学会想到把路由表放在 web.config 配置文件里,这样的话每次在调整的时候只需要修改 web.config 文件就可以了。我也查询了下网上的资料,由于路由表是一个键值队列,需要在 web.config 里添加自定义节点,并且还需要编写这个自定义节点的实现类。我感觉实现思路有些麻烦,所以下面的一种方式就出来了。

我们把路由表信息放在 xml 文件里而不是 web.config 文件里,即使 web.config 事实上也是个xml。这样做的好处,一来不需要编写自定义节点的实现类;二是把路由表单独抽离出来,避免由于路由表的修改而带来误操作影响全局。

我们新建一个PageRoutes文件,继承 RouteBase 类,并实现其方法。主要有2个方法 GetRouteData 和 GetVirtualPath 。这2个方法是什么意思呢,简单地举例说,如果想从 /u/wave 得到 /user.aspx ,调用的是 GetRouteData 方法,如果是从 user.aspx 里得到 /u/wava , 调用的是 GetVirtualPath  方法。后者在 MVC 里用的非常多,在 webform 中,我这里详细描述 GetRouteData  方法,其它的原理是一样的。

我们来新建一个Route.xml文件用来保存路由信息。
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Route>
<Page virtualPath=”/home” routePage=”~/default.aspx” />
<Page virtualPath=”/about” routePage=”~/about.aspx” />
<Page virtualPath=”/u/{userid}/{noteid}” routePage=”~/notedetail.aspx” />
<Page virtualPath=”/u/{userid}” routePage=”~/notelist.aspx” />
</Route>
接下来,我们把精力放在 GetRouteData 方法上,这个方法会拦截所有的请求,如果没有需要处理的,则返回 null 跳过进行后面的操作。下面的代码有点长,来慢慢地解说,

public IRouteHandler RouteHandler { get; set; }

public override RouteData GetRouteData (HttpContextBase httpContext)         {

string xmlPath = httpContext.Server.MapPath (“~”) + “Route.xml”;

if (!File.Exists (xmlPath)) { return null; } //如果配置文件不存在则直接返回

XmlDocument doc = new XmlDocument ( );

doc.Load (xmlPath);

XmlNodeList list = doc.GetElementsByTagName (“Page”);

string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(1).ToLower();

foreach (XmlNode node in list)          {

string n = node.Attributes[“virtualPath”].Value.ToLower();

//第一步,直接比对,优先级最高

if (n== virtualPath) {

var data = new RouteData();

data.RouteHandler = new PageRoute(node.Attributes[“routePage”].Value);

return data; }

//第二步,带 {userId}的参数比对

string v=n;

string o=new Regex(“{(\\w|\\W)+?}”).Replace(v,”(\\w|\\W)+”);

Regex reg = new Regex(o);

if (reg.IsMatch(virtualPath)){

var data = new RouteData();

data.RouteHandler = new PageRoute(node.Attributes[“routePage”].Value);

string[] a = n.Split(new char[] { ‘/’, ‘.’ });

string[] b = virtualPath.Split(new char[] { ‘/’, ‘.’ });

for (int i = 0, j = a.Length; i < j; i++) {

if (a[i].StartsWith(“{“))  {

string d = a[i].Replace(“{“, “”).Replace(“}”, “”);

data.Values[d] = b[i]; }}

return data; }}

return null; }

程序首先是检查xml文件是否存在,如果存在就加载并生成列表,使用当前的 url 在列表里遍历,如果找到了就返回信息。对于有参数的,则找到参数部分,看是否符合要求,符合的话先把参数填充进去,再返回信息。最后,如果都没有找到,则返回 null 跳过进行后面的。

现在,我们只需要在 Global 文件里添加 routes.Add(new PageRoutes()); 这一行就可以了。以后需要调整的时候直接修改 Route.xml 文件即可。至此,webform 中使用 Route 的文章基本上就写完了。

写在后面的话,其实这么写有一个潜在的性能问题,就是每次访问都需要加载 xml 文件,比较好的实现方式是把请求的路由信息放在缓存里,缓存依赖设置为文件类型的,这样的话每当xml有修改的话,缓存就自动失效重新加载 xml 。这个不是很难,就留给各位同学们去实现了。

而对于 GetVirtualPath 方法,我这里并没有去提及,一是对于传统的 webform 来说,用到的机会比较少;二是需要根据具体的项目来定义,这里以通用例子来讲解有误导嫌疑;三是给大家个锻炼的机会。

祝大家编码愉快。

分类: 日常 标签: , ,