注:本文并非绝对原创 大部分内容摘自 http://blog.csdn.net/hengshujiyi/article/details/20943045
文中有些方法可能已过时并不适用于现在的开发环境。
1,Search Bar 怎样去掉背景的颜色(storyboard里只能设置background颜色,可是发现clear Color无法使用)。
其实在代码里还是可以设置的,那就是删除背景view
[[self.searchBar.subviews objectAtIndex:0] removeFromSuperview];
2,NSDate:
1 字母 日期或时间元素 表示 示例 2 G Era 标志符 Text AD 3 y 年 Year 1996 96 4 M 年中的月份 Month July; Jul; 07 5 w 年中的周数 Number 27 6 W 月份中的周数 Number 2 7 D 年中的天数 Number 189 8 d 月份中的天数 Number 10 9 F 月份中的星期 Number 2 10 E 星期中的天数 Text Tuesday; Tue 11 a Am/pm 标记 Text PM 12 H 一天中的小时数(0-23) Number 0 13 k 一天中的小时数(1-24) Number 24 14 K am/pm 中的小时数(0-11) Number 0 15 h am/pm 中的小时数(1-12) Number 12 16 m 小时中的分钟数 Number 30 17 s 分钟中的秒数 Number 55 18 S 毫秒数 Number 978 19 z 时区 General time zone Pacific Standard Time; PST; GMT-08:00 20 Z 时区 RFC 822 time zone -0800
[注意]在开发中,如果使用年月日,用NSDateFormatter setFormat :@"yyyy-MM-dd",如果是使用小时和分钟,设置为:"HH:mm",切记不要设置“HH-mm”,这样会出错的。
举例:
1 //创建一个时间对象 2 NSData * date = [NSDate date]; 3 //打印时间 4 NSLog(@"today is %@",date); 5 6 //再获取的时间date减去24小时的时间(昨天的这个时候) 7 NSDate *yesterday = [NSDate dateWithTimeIntervalSinceNow:-(24*60*60)]; 8 NSLog(@"yesterday is %@",yesterday);//打印昨天的时间 9 10 /*字符串换成时间*/ 11 //设置一个字符串的时间 12 NSString *datestring = [NSString stringWithFormat:@"1999-09-03"]; 13 //想要设置自己想要的格式,可以用nsdateformatter这个类,这里是初始化 14 NSDateFormatter * dm = [[NSDateFormatter alloc]init]; 15 //指定输出的格式 这里格式必须是和上面定义字符串的格式相同,否则输出空 16 [dm setDateFormat:@"yyyy-MM-dd"]; 17 //把字符串的时间转换成Date对象,用dateFromString方法 18 NSDate * newdate = [dm dateFromString:datestring]; 19 //输出 20 NSLog(@"newdate is %@",newdate); 21 22 23 /*把时间转换成字符串*/ 24 //把Date对象转换成String对象 用stringFromDate方法 25 NSString * datestring2 = [dm stringFromDate:newdate]; 26 //打印 27 NSLog(@"datestring2 is %@",datestring2);
3,如果使用 UTTabviewCell,设置其accessory样式为:Detail Disclosure ,就是在每一个cell右边设置一个detail button。如果这样的操作是使用storyboard,进行的,它会要求你给每一个你cell设置indentifier,然后你会在以下方法内设置重用indentfier,别忘记加上一句话,否则编译运行时可能会弹出: cell未实例化
4,在开发项目中,有时有这样的需求:运行程序,登陆界面是一个自由的ViewController,只是摆放几个TextField和button,点击后跳转到孩子选择或其它选择界面,点击选项后进入我们的主界面:这个时候,在登陆界面作跳转时,会有好多的方法,如果使用storyboard,就比较方便了,设置一个segue,跳转代码中:
[self PerformSegueWithIdentifier:@"targetViewController",self]; 就可以了,可是我想实例化想要跳转的控制器,然后设置某一属性的值,这样跳转后控制器获取那个属性,就会得到值了,可是这样做会有一个问题:
主界面控制器如果使用了navigatorViewController,并且是其RootViewController,等到在主界面设置功能,点击某一功能,想push到一个新页面时,问题就来了,你会发现毫无反应,没有报错,只是segue无法跳转。后来终于找到原因:就是我在登陆控制器跳转时没有使用segue的方法,而是用代码self.storyboard,加载一个新类,具体原理目前还没有搞明白,先把出问题的代码记录下来,回头补之:
代码这样做,会导致其后无法使用navigatorViewController做push跳转
5,(1010更新)开发过程中,我们通过http请求,后台返回json数据,而有时数据里某一字段的值为null~,然后我们把此值赋值给NSArray,NSdictionary,或是NSString,然后我们会判断此值为null时,所做的处理,而通常惯性思维判断时我们都会写:if(dict == nil)或是if(dict == Nil)或是if(dict == NULL)再或是if(dict isEqual nil),我们发现,都不好用,根本没有起到判断的作用~后来我才发现,原来不能这样来判断。
简单点说,就是当字典,数组为null时,后台打印的输出结果是这样:
然后,我们需要在代码判断时利用[NSNull null]来判断,具体如:
isEqual:[NSNull null] 就搞定了,nsarray也是同样的道理。
控制台打印:str=(null) 代表着 字符串或数组或字典是一个空指针,(而非空字符串)判断的时候,直接用:
if(str == nil)就可以了。如下图所示:
而控制台打印:str = <null>,代表着这是一个空字符串,赋值为空,指针是存在的,只是内容为空,这种判断需要使用:
if(str is equal [NSNull null ]) ,因为在ios上,内容为空不能简单的判断str==null(null 在ios上得用[NSNull null])
一般这种情况是,服务器那边是null,直接返回@"null"的字符串,这样在ios这边不好判断,最好跟后台沟通,如果遇到null值,返回@"",好做判断
6,给uiview设置圆角样式
只需在加载时,添加这样的话就可以了:
testView.layer.cornerRadius = 6;
testView.layer.masksToBounds = YES;
注意,需要 import <QuartzCore/QuartzCore.h> 导入,否则,不能识别cornerRadius和masksToBounds。
uiview设置背景图片:
[theMainView setBackgroundColor: [UIColor colorWithPatternImage: [UIImage imageNamed: @"bg.png"]]];
imageName 缓存,下面方法不缓存
1 NSString *thePath = [[NSBundle mainBundle] pathForResource:@"default" ofType:@"jpeg"]; 2 UIImage *prodImg = [[UIImage alloc] initWithContentsOfFile:thePath"]; 3 controller.productImg.image = prodImg; 4 [prodImg release];
7,隐藏键盘的两种方法
1-1Did End On Exit 调用下面事件当点击键盘return得时候就会隐藏键盘
1 - (IBAction)textFieldShouldReturn:(UITextField *)textField { 2 //[sender resignFirstResponder]; 3 if (textField == chi) { 4 [chi resignFirstResponder]; 5 double m=[chi.textdoubleValue]/3.003; 6 double f=m *3.2808; 7 meter.text=[[NSStringalloc] initWithFormat:@"%.4f",m]; 8 feet.text=[[NSStringalloc] initWithFormat:@"%.4f",f]; 9 } 10 if (textField == meter) { 11 [meter resignFirstResponder]; 12 13 } 14 if (textField == feet) { 15 [feet resignFirstResponder]; 16 } 17 }
1-2 点击屏幕得时候隐藏键盘
1 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 2 UITouch *touch=[[event allTouches] anyObject]; 3 if (touch.tapCount >=1) { 4 [chi resignFirstResponder]; 5 [meter resignFirstResponder]; 6 [feet resignFirstResponder]; 7 } 8 }
1-2 的方法相当于屏幕任何位置的点击事件(除了各组件的点击处)可以在这个方法里执行要隐藏或remove的view。
1-3 隐藏键盘 方法二
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [self.view endEditing:YES]; }
8,UITextField密文显示输入内容:
只需要在TextField属性中的Secure(安全的)勾选上或者设置 passWordTextField.secureTextEntry=YES; 就可以了。显示apple默认的密文显示方式。
9,通过系统自带的NSPredicate使用正则表达式。(在TextField中)
1 NSString *regex =[NSString stringWithFormat:@"^1(3[4-9]|5[012789]|8[2378]|47)\\d{8}$"]; 2 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex]; 3 BOOL isMatch = [predicate evaluateWithObject:editPhoneField.text];
10,项目设置应用程序显示名称:
1,在项目的Supporting Files下寻找infoPlist.strings文件,打开后会看到一片空白(英文默认是跟随项目名称显示)。此时,可以就地添加一句代码:CFBundleDisplayName="爱贝通";这样的话,无论手机设置英文语言还是中文语言,应用程序都会显示设置的名称。
2,为了国际化而言,我们最好创建一个chinese专有的infoPlist.strings文件。
如上图所示,添加一个中文的plist
然后打开添加代码:
这个时候,大功告成。部署在模拟器或真机中吧,你的手机设置(中/英)文语言,它就会调用相应的配置文件。
11更改Xcode的缺省公司名
1 // testAppDelegate.m 2 // test 3 // 4 // Created by gaohf on 11-5-24. 5 // Copyright 2011 __MyCompanyName__. All rights reserved.
在终端中执行以下命令:
defaults write com.apple.Xcode PBXCustomTemplateMacroDefinitions ‘{"ORGANIZATIONNAME" = "COMPANY";}‘
执行后效果
1 // testAppDelegate.m 2 // test 3 // 4 // Created by gaohf on 11-5-24. 5 // Copyright 2011 COMPANY. All rights reserved.
12,在有uinavigation,uitoolbar的情况下,如何添加一个全屏的 uiview (一般是作为显示一个进度框,任何区域无法触摸而使用)
只需要在要添加view时侯这样写:
[[UIApplication sharedApplication].keyWindow addSubview:waitingview];
这样,直接把waitingview添加到了uiWindow上,而不是self.view上。再次运行,会发现屏幕全部区域都已经遮挡住了。
13,使用了storyboard,运行程序模拟器显示黑屏,这是由于,操作不当,获取点击了例如 navigationViewController属性种的in init ViewController选项,然后重置了当前进入程序后的首界面,解决办法就是选择入口界面,属性种重新勾选此选项。
StoryboardApp[8593:207] Failed to instantiate the default view controller for UIMainStoryboardFile ‘MainStoryboard‘ - perhaps the designated entry point is not set?
StoryBoard中没有一个view controller设置了Initial Scene。您需要选择一个view conroller作为story board的第一个界面:
14,如何给uiNavigationBar 设置背景颜色或是自定义图片?
在项目中添加如下代码:
//设置背景颜色:
1 UIColor *itemcolor = [UIColor colorWithRed:100.0f/255.0f green:176.0f/255.0f blue:0.0f/255.0f alpha:0.3f]; 2 self.navigationController.navigationBar.tintColor = itemcolor;
//设置自定义的图片:
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"navbg.png"] forBarMetrics:UIBarMetricsDefault];
5.0以上,api有了上面setBackgroundImage的方法,可以直接设置,如果项目需要适配5.0以下版本的设备,最好加一个判读,是否有此函数,有则设置,没有就通过drawRect方法设置。
另外:设置背景图片无法匹配backButton或rightButtonItem,所以返回按钮或右边自定义的Bar button Item需要自行处理。
15,如何给uiview设置背景图片?
在storyboard或xib中,添加一个uiview,属性设置栏一般都有设置背景颜色,样式,透明度alpha,但是没有提供设置image,只有在imageview中才有,所以,要想设置背景图片,只能在代码中设置,如下:
[leftNaviView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"pabb_leftnaviview_bg.png"]]];
这样,背景就可以变成想要的图片了。另外,设置大小:
[leftNaviView setFrame:CGRectMake(9, 60, 120, 250)];
效果图:
16如何在项目用代码打开AppStore软件(也就是访问appstore)
1 //以下是通过id打开此软件的评价 2 // int m_appleID = 576337094; 3 // NSString *str = [NSString stringWithFormat: 4 // @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%d", 5 // m_appleID ]; 6 7 //以下是通过appstore链接到自己应用在商店的位置 8 NSString *url = [NSString stringWithFormat:@"http://itunes.apple.com/cn/app/huo-xing-she-xin-dian/id549425594?l=en&mt=8"]; 9 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
把以上代码直接拷贝到想要实现点击跳转的操作方法内就可以了,通过appID,随意可以通过appstore打开应用,直接用url就可以链接到了。很简单,一般都用在检查更新的时候。
17,如何代码实现点击http://www.kaka.com或400-800-400或message实现跳转safari,phone或message?
只需要在相应的代码中写入:
1、调用 电话phone
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://4008008288"]];
2、调用自带 浏览器 safari
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.abt.com"]];
3、调用 自带mail
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://[email protected]"]];
4、调用 SMS
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms://800888"]];
5,跳转到系统设置相关界面
1 [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=WIFI"]];
其中,发短信,发Email的功能只能填写要发送的地址或号码,无法初始化发送内容,如果想实现内容的话,还需要更复杂一些,实现其各自的委托方法。
若需要传递内容可以做如下操作:
1 //加入:MessageUI.framework 2 #import <MessageUI/MFMessageComposeViewController.h> 3 4 //实现代理:MFMessageComposeViewControllerDelegate 5 6 //调用sendSMS函数 7 //内容,收件人列表 8 - (void)sendSMS:(NSString *)bodyOfMessage recipientList:(NSArray *)recipients 9 { 10 11 MFMessageComposeViewController *controller = [[[MFMessageComposeViewController alloc] init] autorelease]; 12 13 if([MFMessageComposeViewController canSendText]) 14 15 { 16 17 controller.body = bodyOfMessage; 18 19 controller.recipients = recipients; 20 21 controller.messageComposeDelegate = self; 22 23 [self presentModalViewController:controller animated:YES]; 24 25 } 26 27 } 28 29 // 处理发送完的响应结果 30 - (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result 31 { 32 [self dismissModalViewControllerAnimated:YES]; 33 34 if (result == MessageComposeResultCancelled) 35 NSLog(@"Message cancelled") 36 else if (result == MessageComposeResultSent) 37 NSLog(@"Message sent") 38 else 39 NSLog(@"Message failed") 40 }
发送邮件的为:
1 //导入MFMailComposeViewController 2 #import <MessageUI/MFMailComposeViewController.h> 3 //实现代理:MFMailComposeViewControllerDelegate 4 5 //发送邮件 6 -(void)sendMail:(NSString *)subject content:(NSString *)content{ 7 MFMailComposeViewController *controller = [[[MFMailComposeViewController alloc] init] autorelease]; 8 9 if([MFMailComposeViewController canSendMail]) 10 11 { 12 13 [controller setSubject:subject]; 14 15 [controller setMessageBody:content isHTML:NO]; 16 17 controller.mailComposeDelegate = self; 18 19 [self presentModalViewController:controller animated:YES]; 20 21 } 22 } 23 24 //邮件完成处理 25 -(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{ 26 27 [self dismissModalViewControllerAnimated:YES]; 28 29 if (result == MessageComposeResultCancelled) 30 NSLog(@"Message cancelled"); 31 else if (result == MessageComposeResultSent) 32 NSLog(@"Message sent"); 33 else 34 NSLog(@"Message failed"); 35 36 } 37
默认发送短信的界面为英文的,解决办法为:在.xib 中的Localization添加一組chinese
18,注册设置应用程序访问用户手机发送推送消息,(弹出Alertview)
1 [[UIApplication sharedApplication] registerForRemoteNotificationTypes: 2 (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
19,轻松自定义复选框按钮
1 -(void)checkboxClick:(UIButton *)btn 2 { 3 btn.selected = !btn.selected; 4 } 5 6 7 - (void)viewDidLoad { 8 UIButton *checkbox = [UIButton buttonWithType:UIButtonTypeCustom]; 9 10 CGRect checkboxRect = CGRectMake(135,150,36,36); 11 [checkbox setFrame:checkboxRect]; 12 13 [checkbox setImage:[UIImage imageNamed:@"checkbox_off.png"] forState:UIControlStateNormal]; 14 [checkbox setImage:[UIImage imageNamed:@"checkbox_on.png"] forState:UIControlStateSelected]; 15 16 [checkbox addTarget:self action:@selector(checkboxClick:) forControlEvents:UIControlEventTouchUpInside]; 17 [self.view addSubview:checkbox]; 18 }
20,程序中获取软件的版本号和app名称
应用程序的名称和版本号等信息都保存在mainBundle的infoDictionary字典中,用下面代码可以取出来。
1 NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary]; 2 NSString* versionNum =[infoDict objectForKey:@"CFBundleVersion"];//版本名称 3 NSString*appName =[infoDict objectForKey:@"CFBundleDisplayName"];//app名称
1 <p style="margin-top: 0px; margin-bottom: 0px; font-size: 11px; font-family: Menlo;"> 2 <span style="color: #703daa">NSString</span> 3 * versionShortString = [infoDict <span style="color: rgb(61, 29, 129);">objectForKey</span>: 4 <span style="color: #d12f1b">@"CFBundleShortVersionString"</span>];//标识应用程序发布版本号 5 </p> 6 NSString*text =[NSString stringWithFormat:@"%@ %@",appName,versionNum, 7 <span style="font-family: Menlo; font-size: 11px; white-space: pre; ">versionShortString</span>];
此version 为工程info下的Bundle version字段值:value可以随意定义。
CFBundleVersion,标识(发布或未发布)的内部版本号。这是一个单调增加的字符串,包括一个或多个时期分隔的整数。
CFBundleShortVersionString 标识应用程序的发布版本号。该版本的版本号是三个时期分隔的整数组成的字符串。第一个整数代表重大修改的版本,如实现新的功能或重大变化的修订。第二个整数表示的修订,实现较突出的特点。第三个整数代表维护版本。该键的值不同于“CFBundleVersion”标识。
图片里的 Version 对应的就是CFBundleShortVersionString (发布版本号 如当前上架版本为1.1.0 之后你更新的时候可以改为1.1.1)
Build 对应的是 CFBundleVersion(内部标示,用以记录开发版本的,每次更新的时候都需要比上一次高 如:当前版本是11 下一次就要大于11 比如 12,13 ....10000)
21,如何使屏幕一直保持唤醒状态?(就是不自动黑屏)
比如,如果我们做一个播放视频的功能时,想在播放的时候,不会自动进入屏保(黑屏)
只要在代码里加入这一行:
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
当然,在想要黑屏的时候还需要把它设置为NO(比如视频播放完毕时),不然屏幕会在此软件运行下一直亮着。
22,一直以来的疑问:在Xcode中,有时候在类名称后边带有M或C等标示,不知道为何意。如下图所示:
表示在版本控制中,自上一次提交以来,文件做了修改。貌似只有在带有版本控制的项目代码中才会显示。
23,有关ios上屏幕旋转,view设置Frame的相关问题(ios5)。
屏幕旋转一共有4个相关属性(旋转方向):
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
前两个是横屏时的状态,后两个是正常状态(Portrait)和上下颠倒(UpsideDown)时的状态。
【注意:Left和Right两个左右模拟器旋转时移动的方向正好是相反的,但移动后Home的方向,就如下图所示】
具体见下图:
其中涉及到两个方法,在ViewController中默认会实现这个方法:
1 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 2 { 3 //除了不允许旋转屏幕后:上下颠倒,其余方向都运行旋转 4 //如果想都运行,可以直接返回YES,或都不允许NO 5 return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); 6 7 }
这个方法是声明此ViewController所运行屏幕旋转的方向,一共4种类型,全部允许返回YES,上图所示除了不允许上下颠倒,其余都可以。【注意,项目设置Supported Device Orientations 所支持的屏幕旋转类型并不影响此方法的设置,也就是说,哪怕Support只支持Portrait,方法里设置UpsideDown,此ViewController也会实现上下颠倒旋转的】
第二个方法,是我们比较常用的,也就是在设备即将以某个方向旋转之前,我们在其状态(方向)设置组件或view的Frame,bound,等需要改变的属性时所用到的方法。
1 -(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{ 2 3 //屏幕旋转到横屏时 4 if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) { 5 myMapview.frame = CGRectMake(0,0,480, 300); 6 } 7 //屏幕旋转到竖屏时 8 else{//== else if(UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) 9 myMapview.frame = CGRectMake(0, 0, 320,460); 10 } 11 12 }
所有旋转屏幕后需要改变组件尺寸属性的设置都可以在这个方法里面实现。
【注意,以上两个方法,在最新的ios6貌似已经不提倡使用了,除非要适应旧设备,新的旋转屏幕的相关方法可以网络搜索一下】
http://blog.csdn.net/zzfsuiye/article/details/8251060 IOS6屏幕旋转详解(自动旋转、手动旋转、兼容IOS6之前系统)
http://blog.csdn.net/huifeidexin_1/article/details/7826159 ios旋转屏幕总结 详细教程
http://blog.csdn.net/xiaoyun8822/article/details/8213738 Ios5(三)屏幕的旋转和大小设置;
以上为参考教程
24,Xcode编译警告和错误解决方法:
1 Application windows are expected to have a root view controller at the end of application launch
解决方法:在ios5以上版本,应用程序加载时,需要一个 root view controller ,所以需要编写代码
_rootViewController = [[RootViewController alloc] init];
self.window.rootViewController = _rootViewController;
此问题大多是在Xib或Storyboard下操作ViewController时不小心连接RootViewController 的底层View所导致的,检查删除没有作用的view连接线,或是Clean (Command+Shift+K),再运行。
25,如何设置视图(view)在最上层?或是view1和view2交换?
情景再现:
我们在storyboard的一个视图里添加了一个view1用作快捷功能导航;然后在对应的viewController里实例化了一个Mapview的地图view2,大小是整个屏幕,这样一来,就把我们在storyboard中添加的view1覆盖了,这个时候,我们想把view1在地图view2的上面,该怎么做?
简而言之就是window中subview的交换。
首先通过:NSLog(@"subviews:%@",self.view.subviews); 这个我们可以看到当前下所有的subview(NSArray类型)如下图所示:
可以看到一共有3个view:UILabel 地图view2,添加的view1
我们现在要做的就是把后两者对调一下,所以在self.view 中寻找一下看有没有replace相关的方法
就是这个方法,第一个参数是要进行调换的地图view2,第二个参数是调换后显示的view1。
[self.viewexchangeSubviewAtIndex:1 withSubviewAtIndex:2];
因为通过log打印,我们已经知道Mapview在第一个下标的位置,view1在第二个下标的位置。
大功告成。记住这个方法:self.view exchangeSubviewAtIndex:withSubviewAtIndex:];
26,如何隐藏UINavigationBar
有的时候,我们的视图使用了Navigation Controller ,但是主界面(rootviewcontroller)或其它push进入的界面 想使用一个全屏的view,就是说,不显示顶部的navigationBar,这个时候,就需要我们来隐藏了。
1 //隐藏NavigationBar 2 -(void) viewWillAppear:(BOOL)animated{ 3 [self.navigationControllersetNavigationBarHidden:YESanimated:YES]; //设置隐藏 4 5 [super viewWillAppear:animated]; 6 } 7 8 -(void) viewWillDisappear:(BOOL)animated{ 9 [self.navigationControllersetNavigationBarHidden:NOanimated:YES]; 10 11 [super viewWillDisappear:animated]; 12 }
27,如何限制UITextField输入长度(监听textField文本变化的事件)
1、实现UITextFieldDelegate协议;
2、实现textField:shouldChangeCharactersInRange:replacementString:方法;
1 -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{ 2 int kMaxLength = 11; 3 4 NSInteger strLength = textField.text.length - range.length + string.length; 5 //输入内容的长度 - textfield区域字符长度(一般=输入字符长度)+替换的字符长度(一般为0) 6 return (strLength <= kMaxLength); 7 8 }
如上代码,如果我们简单的这样写: if(range.location<=11) return 或是 if (textfield.text.length>=11) 这样虽然也能限制位数为11位,但是如果通过放大镜把光标切换到之前的位数后,你照样可以输入,并且还会导致输入11位后,键盘上的退格(X键)无法使用,原因是:我们在location到达11位后,返回了NO,键盘无法相应:添加,修改,删除。这是很严重的。所以照着我上面的。
方法解读:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
功能:
把textField中位置为range的字符串替换为string字符串;
此函数在textField内容被修改时调用;
返回值:
YES,表示修改生效;NO,表示不做修改,textField的内容不变。
参数说明:
textField:响应UITextFieldDelegate协议的UITextField控件。
range: UITextField控件中光标选中的字符串,即被替换的字符串;
range.length为0时,表示在位置range.location插入string。
string: 替换字符串; string.length为0时,表示删除。
28,使用ios5.0以后的一个方法自定义table View Cell
1 UINib *nib = [UINib nibWithNibName:@"TvWeiboCell" bundle:nil]; 2 [tableView registerNib:nib forCellReuseIdentifier:CellIdentifier];
29,iOS和iPad各app图标和启动页尺寸。
iphone APP图标尺寸:57X57 高清:114X114 单位:pixel 命名:无特殊要求,最好是,app_icon 高清的要加@2x
iphone 启动页尺寸:大小最好是320X460或320X480(相当于整个屏幕尺寸) 单位:pixel 命名:Default.png
iPad APP图标尺寸:72X72 高清:144X144 单位:pixel 命名:
ipad 启动页尺寸:大小最好是768X1004或768X1024 单位:pixel 命名:Default-Portrait~ipad.png 高清:[email protected]~ipad.png
30,如何用NSLog输出NSRange,CGRect等结构体。
NSString 中的方法:
NSStringFromCGPoint
NSStringFromCGSize
NSStringFromCGRect
NSStringFromCGAffineTransform
NSStringFromUIEdgeInsets
如:NSLog(@"rect1: %@", NSStringFromCGRect(rect1));
31,如何在navigationviewcontroller中,pop到之前不同的viewcontroller(push过的viewcontroller)?
如上图所示,回退到界面2,很简单: [self.navigationControllerpopViewControllerAnimated:YES]; 直接就回退到界面2了,可是我们既不想回到rootviewcontroller,
也不想回到界面2,只想回到界面1,该如何做?
笨方法:在界面1要跳转到界面2时,把自己self,set到界面2(前提界面2要设置一个id类型的属性,用来存放界面1self,以此类推,当在界面3想退到界面1时,
[self.navigationControllerpopToViewController:controlleranimated:YES];
其实现在刚明白,一个很简单的方法:
1 NSArray *viewControllers=[self.navigationController viewControllers]; 2 UIViewController *controller=[viewControllers objectAtIndex:1];
想起来navigation的机制了吧,每当我们push到一个viewcontroller时,就会把这个viewcontroller的实例保存到nsarray里,通过array可以获取到任何一个viewcontroller,
这不就解决问题了么?
[self.navigationController popToViewController:controller animated:YES];
【注意】千万不要在这个地方实例化 界面1 然后popToViewController,这种方法是不对的。
32,self.navigationItem.backBarButtonItem 的title设置
新写的App中需要使用UINavigationController对各个页面进行导航,但由于第一级页面的title较长,在进入第二级页面后返回按钮leftButtonItem的title就会变得很长,
对NavigationBar空间占用很大,而且不美观,于是使用代码对leftButtonItem的title文本进行修改,无论是设置self.navigationItem.leftBarButtonItem.title = @"返回";还是self.navigationItem.backBarButtonItem.title = @"返回";都没有效果,title文本始终不会发生变化。到网上乱搜一通后,得到了以下解决方法,相对来说比较简单,特记录如下:
在第一级页面的viewDidLoad方法中加入以下代码:
1 UIBarButtonItem *temporaryBarButtonItem = [[UIBarButtonItem alloc] init]; 2 temporaryBarButtonItem.title =@"返回"; 3 self.navigationItem.backBarButtonItem = temporaryBarButtonItem; 4 [temporaryBarButtonItem release]; 5 // 也就是用一个新的按钮在进行导航前将原来的返回按钮替换掉就可以了。
所以,通过这个我们可以明白,self.navigationItem.backBarButtonItem是在一级页面设置的(提前设置下一个页面的返回按钮),而self.navigationItem.leftBarButtonItem/rightBarButton是在二级页面设置的,(随意设置本页面的左右按钮,左按钮将替代系统的返回按钮)
---------------------------------------------------------------------------------------------------------
一般一个程序中有一个UIWindow,一个UINavigationController,一个根UIViewController,多个子UIViewController。
UIWindow是整个可视界面的容器,里面放置我们看到的UIView。
UIView负责处理屏幕上一个矩形区域的绘制,UIView中还可包含子UIView。
UIWindow是UIView类的扩展,可以看作是整个屏幕的根UIView。
UIViewController负责管理UIView的层次结构。可以有多个UIViewController。
一个UIViewController中有一个顶部的UINavigationBar、一个根UIView,多个子UIView。
UINavigationBar中有一个UINavigationItem,UINavigationItem。
UINavigationController是用于构建分层应用程序的主要工具,它维护了一个UIViewController栈。
这个栈中必须有一个根UIViewController,其他的UIViewController都是子UIViewController。
UINavigationItem表示UINavigationBar中的控件,比如左按钮、中间标题、右按钮。
UINavigationController会自动在当前子UIViewController的UINavigationBar左边添加一个返回按钮。
按钮名称是上一个UIViewController的标题。
---------------------------------------------------------------------------------------------------------
33,self.navigationItem和self.navigationController.navigationItem的区别?
/**********************************************/
self.navigationItem
self.navigationController.navigationItem
self.navigationController.navigationBar
/**********************************************/
1, 不要混淆 self.navigationItem 和 self.navigationController.navigationItem ,
UINavigationItem 本身是用来 定制 ViewController自己在被导航过程中的 appearence, navigationItem是UIViewController类关于UINavigationControllerItem类别的扩展:
@interface UIViewController (UINavigationControllerItem)
@property(nonatomic,readonly,retain)UINavigationItem * navigationItem;
...
@end
所以后者 是调用 VC的所在的导航控制器导航控制器自己自己作为VC的 navigationItem,是导航的叠加。
2. UINavigationBar 继承于 UIView,隶属于整个 UINavigationController ,用来定义整个导航过程中的导航栏的颜色等其他数值,(类似于 self.tabBarController.tabBar UINavigationBar ,只需要一个设置通用的基本属性),只能通过self.navigationController.navigationBar来访问。
因此,定制于导航堆栈里某个VC 的时候,一般通过self.navigationItem, 比如常用的self.navigationItem.leftBarButtonItem,self.navigationItem.rightButtonItem, 同时如果自己来定制导航栏的外观的话,就要用到self.navigationItem.titleView,这个可以直接用一个 CustomView 赋值于self.navigationItem.titleView即可。
此时,如果需要,就得自己画导航过程中的返回按钮了。
34,图片模糊化处理
1 2 +(UIImage *)scale:(UIImage *)image toSize:(CGSize)size 3 { 4 UIGraphicsBeginImageContext(size); 5 [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; 6 UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext(); 7 UIGraphicsEndImageContext(); 8 return scaledImage; 9 }
35,NSString转换大小写的用法
iOS 6中NSString对象有些新的使用方法,可以让字符串转变成全部大写,全部小写,或者每个单词首字母大写。
代码如下所示:
1 NSString *str = @"mobile developer tips"; 2 // Convert string to uppercase 3 NSString *upperStr = [str uppercaseStringWithLocale:[NSLocale currentLocale]]; 4 NSLog(@"upperStr: %@", upperStr); 5 6 // Convert string to caps 7 NSString *capStr = [upperStr capitalizedStringWithLocale:[NSLocale currentLocale]]; 8 NSLog(@"capStr: %@", capStr); 9 10 // Convert string to lowercase 11 NSString *lowerStr = [capStr lowercaseStringWithLocale:[NSLocale currentLocale]]; 12 NSLog(@"lowerStr: %@", lowerStr);
运行结果:
36,如何获取手机硬件信息?
通过使用UIDevice:
[[UIDevice currentDevice] systemName];
[[UIDevice currentDevice] systemVersion];//os version
[[UIDevice currentDevice] uniqueIdentifier];
[[UIDevice currentDevice] model];
[[UIDevice currentDevice] name];
真机上结果:
System Name: iPhone OS
System Version: 4.2.1
Unique ID: 9b5ded78d5fa0ac96250f8b4af0e46f40b96ea6d
Model: iPhone
Name: “wwk”的 iPhone
模拟器上结果:
System Name: iPhone OS
System Version: 4.2
Unique ID: 21FFE0FF-429B-5D0B-96D2-EADCA3203260
Model: iPhone Simulator
Name: iPhone Simulator
uniqueIdentifier:iPhone通过,向几个硬件标识符和设备序列号应用内部散列算法,而生成这一标识符。
http://blog.csdn.net/qiwancong/article/details/7914923 参考
36,真机调试:could not change executable permissions错误?
虽然更改了新demo的bundle identifier和之前的identifier一样,但是真机上还保留着之前调试时的demo,所以新的工程如果使用同样的identifier真机调试,需要先把机器上原来的demo删除,再使用新工程调试。
37,判断iphone5屏幕的宏定义
1 #define iPhone5 ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(640, 1136), [[UIScreen mainScreen] currentMode].size) : NO)
在需要判断屏幕尺寸的地方:
mymapview = [[BMKMapView alloc] initWithFrame:CGRectMake(0,0,320,460+(iPhone5?88:0))];
iphone5的View为568,减去Nav(44)+任务栏(20),为504,相比iphone4s及以前版本的480,减去Nav+任务栏,为416,高出88(差别).
http://www.cnblogs.com/maxfong/archive/2012/10/04/2711379.html
38、invalid deployment target for -stdlib=libc++ (requires iOS 5.0 or later)错误
选中项目--target---build settings 找到C++Standard Library 改成:Compiler Default,再编译就不会有错误了.
39,如何调用系统声音?【iphone 调用系统铃声与震动功能】
首先要在工程里加入Audio Toolbox framework这个库,然后在需要调用的文件里
#import <AudioToolbox/AudioToolbox.h>
最后在需要播放提示音的地方编写如下代码:
AudioServicesPlaySystemSound(1000);//新邮件消息提示
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); //震动
注:括号中为系统声音的id,详见请参考以下网址http://iphonedevwiki.net/index.php/AudioServices。
http://blog.csdn.net/tskyfree/article/details/8096500
http://www.cnblogs.com/martin1009/archive/2012/06/14/2549473.html
http://www.cnblogs.com/chen1987lei/archive/2012/02/07/2341535.html
40,重复调用2次loadView和viewDidLoad
最好不要在UIViewController的loadView方法中改变状态栏的可视性(比如状态栏由显示变为隐藏、或者由隐藏变为显示),因为会导致重复调用2次loadView和viewDidLoad方法。
//错误代码 1 - (void)loadView { 2 NSLog(@"loadView"); 3 // 隐藏状态栏 4 [UIApplication sharedApplication].statusBarHidden = YES; 5 6 // .... 创建UIView 7 self.view = [[[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds] autorelease]; 8 self.view.backgroundColor = [UIColor grayColor]; 9 } 10 11 - (void)viewDidLoad { 12 [super viewDidLoad]; 13 NSLog(@"viewDidLoad"); 14 }
打印信息:
1 2013-05-14 00:51:36.152 test[2251:c07] loadView
2 2013-05-14 00:51:36.153 test[2251:c07] loadView
3 2013-05-14 00:51:36.153 test[2251:c07] viewDidLoad
4 2013-05-14 00:51:36.154 test[2251:c07] viewDidLoad
虽然运行效果是对的,但是系统连续调用了2次loadView和viewDidLoad方法,导致创建了2次UIView,造成了不必要的开销。
原因分析:
状态栏由显示变为隐藏,意味着屏幕的可用高度变长了,UIViewController的UIView的高度也要重新调整,因此系统会重新调用loadView方法创建UIView,
创建完毕后再次调用viewDidLoad方法。
41,点击UIButton 无法产生触摸事件
如果在UIImageView中添加了一个按钮,你会发现在默认情况下这个按钮是无法被点击的,需要设置UIImageView的userInteractionEnabled为YES:
imageView.userInteractionEnabled = YES;
设置为YES后,UIImageView内部的按钮就可以被点击了
42,如何启动app时全屏显示Default.png(图片)?
大部分app在启动过程中全屏显示一张背景图片,比如新浪微博会显示这张:
要想在iOS中实现这种效果,毫无压力,非常地简单,把需要全屏显示的图片命名为Default.png即可,在iOS app启动时默认会去加载并全屏显示Default.png。
也可以用其他名称来命名图片,在Info.plist配置一下即可:
配置过后,app启动时就会去加载并全屏显示lufy.png
在默认情况下,app显示Default.png时并非真正的"全屏显示",因为顶部的状态栏并没有被隐藏,比如下面的效果:
大部分情况下,我们都想隐藏状态栏,让Default.png真正全屏显示。
说到这里,可能有人马上就想到了一种办法:在AppDelegate的application:didFinishLaunchingWithOptions:方法中添加如下代码:
[UIApplication sharedApplication].statusBarHidden = YES;
我只能说你的思路是对的,但实际上达不到想要的效果,你会发现显示Default.png时状态栏还是存在的,等Default.png显示完毕后,状态栏才被隐藏。
我先解释下为什么这种方法不可行,其实原因很简单:
1> Default.png是在app启动过程中加载的,并不是在app启动完毕后再加载的
2> AppDelegate的application:didFinishLaunchingWithOptions:方法是在app启动完毕后才调用的
下面说一下解决方案,在Info.plist中增加一个配置即可:
这里的YES表示在app初始化(启动)的时候就隐藏状态栏。
当然,在Default.png显示完毕后状态栏还是隐藏的。如果想重新显示状态栏,补上下面代码即可:
[UIApplication sharedApplication].statusBarHidden = NO;
43,使用ASIHTTPRequest保存cookies
假如我的APP,第一次启动请求了登录接口并得到了Cookie,然后我把APP关了,下次启动APP,我不请求登录接口了,那上次得到的Cookie就不存在了。如果需要,那么2种方法,下次启动app,自动登入,这样能得到服务器分配给你的cookier(这一种是最好的,因为session也会过期),还有一种是你把上次登入的时候,拿到的cookier存起来,然后下次启动app的时候,手动给请求(ASIHTTP)添加cookie。
所以当第一次登录成功后,可以把cookie保存到CoreData,SQLite,UserDefault等,等到下次网络请求时,读取:
1 ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:UserInfoURL]; 2 [request setRequestMethod:@"POST"]; 3 [request addRequestHeader:@"Cookie" value:[NSString stringWithFormat:@"cookie=%@",[[NSUserDefaults standardUserDefaults] objectForKey:@"cookie"]]]; 4 //把cookie的值放进Header里,这个cookie的值是一串很长的字符串。
44,设置UITextField只有当有字符输入后,键盘右下角的搜索/返回/done/等等键才可以使用
TextField设置这个属性为YES就可以了,默认为NO
searchField.enablesReturnKeyAutomatically =YES;
45.类似QQ等IM软件,长度和高度不一的聊天气泡的图片是如何做的?拉伸?
其实是一个小气泡png,然后拉伸中间部分,四个角不拉动,就是局部拉伸。ios自带方法,四个角可以不拉伸的,如下:
46,UITableView中有多个UITextField时,被挡住的TextField如何实现自动向上弹起?
首先要实现TextField的delegate,在方法:
1 - (void)textFieldDidBeginEditing:(UITextField *)textField { 2 [self.tableView setContentOffset:CGPointMake(0, 70) animated:YES]; 3 4 }
这说明当开始输入时,tableview在原来的基础上向上抬起70个距离。多个UITextFiled可以通过判断来使用CGPoint的调整高度,我这写的是70.
tableview的scrollEnabled属性一定要是YES;要不然滚动不了了。
记得在return时复原tableview的位置:
1 - (BOOL)textFieldShouldReturn:(UITextField *)sender { 2 [self.tableView setContentOffset:CGPointMake(0, 0) animated:YES]; 3 return YES; 4 }
47,ios如何在调试时,轻松找到程序在哪里崩溃?
我们给自己的工程添加一个全局的断点:
一步步按上面图完成操作。
再运行程序
自动就断点到这里来了,
log信息是:
2013-05-20 11:14:19.635 GestureRecognizer[1491:c07] -[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance 0x7a88df0 2013-05-20 11:15:21.148 GestureRecognizer[1491:c07] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException‘, reason: ‘-[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance 0x7a88df0‘
这样很简单就能发现程序崩溃是因为value没有 isEqualToString方法。如果没加上面这个通用的断点,那程序会直接断点到main函数去。
48,UIImageView 如何实现windows 桌面类似的背景壁纸屏幕(很小的图片会显示N多个)?
从UImageView上找ContentMode或clipToBounds是都不管用的,正确的办法是,不用UImageView,使用UIView,然后设置backgroundColor属性为我们的图片,这样的话自动会以屏幕的方式显示。
1 UIView *gridView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 195)]; 2 gridView.backgroundColor = [UIColor colorWithPatternImage:BUNDLE_IMAGE(@"blue_grid")]; 3 [self.view addSubview:gridView]; 4 [gridView release];
下图所示:(原图是一个6X6的方格)
49,UITableViewCell 的backgroundColor不起作用的问题?
在开发时,想要在tableview中的某一个Cell设置选中状态,并且Cell的背景颜色是一个自定义颜色。
1 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 2 3 <span style="white-space:pre"> </span>//省略.... 4 5 cell.textLabel.font = [UIFont systemFontOfSize:6.0]; 6 cell.textLabel.text = @"13832207020"; 7 8 if (indexPath.row==0) { 9 10 [cell setBackgroundColor:[UIColor colorWithRed:100.0f/255.0f green:176.0f/255.0f blue:0.0f/255.0f alpha:1.0f]]; 11 } 12 else{ 13 [cell setBackgroundColor:[UIColor whiteColor]]; 14 } 15 16 return cell; 17 }
这样的话,第1行cell就应该是我们设置好的颜色,不过请注意,此方法在UITableViewStylePlain的风格下有效,在 UITableViewStyleGrouped的样式下是无效的!这个跟tableview的backgroundView和backgroundColor是没有关系的,个人猜想应该是在Grouped风格下,cell选中的颜色有系统的view遮罩,导致我们设置的无法显示出来。
【补充】如果想在reload或init时设置tableview的某一cell为 selected状态,千万不要使用cell setSelected:YESanimated:YES,使用tableview的方法:
1 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; 2 terminalTableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
50,UITableViewCell选中时contentView中各组件的高亮状态
使用系统或简单自定义的UITableViewCell时,当选中某一行Cell后,除了背景颜色改变外,Cell上所有的组件(数据)比如UILabel,UIbutton等都被自动显示成了其
Highlighted(高亮)状态下的效果,(如果想显示出效果,你的那些自定义的组件必须要设置高亮状态,比如highlightedTextColor,UIControlStateHighlighted等),所以这一点需要特别注意,如果不想要系统的这个自动特效,有两个解决办法:
1,组件不设置highlighted下的属性
2,如果自定义的Cell:
1 - (void)setSelected:(BOOL)selected animated:(BOOL)animated 2 { 3 4 [super setSelected:selected animated:animated]; 5 6 if (selected) { 7 //强制系统在UITableViewCell选中时SettingButton组件的高亮状态为NO 8 [(UIButton *)[self.contentView.subviews objectAtIndex:1] setHighlighted:NO]; 9 [settingBtn setImage:BUNDLE_IMAGE(@"accessory_sel") forState:UIControlStateNormal]; 10 } 11 else{ 12 [settingBtn setImage:BUNDLE_IMAGE(@"accessory_nor") forState:UIControlStateNormal]; 13 } 14 15 16 }
51,IOS atomic与nonatomic,assign,copy与retain的定义和区别
atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。
atomic
设置成员变量的@property属性时,默认为atomic,提供多线程安全。
在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。加了atomic,setter函数会变成下面这样:
{lock}
if (property != newValue) {
[property release];
property = [newValue retain];
}
{unlock}
nonatomic
禁止多线程,变量保护,提高性能。
atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。
指出访问器不是原子操作,而默认地,访问器是原子操作。这也就是说,在多线程环境下,解析的访问器提供一个对属性的安全访问,从获取器得到的返回值或者通过设置器设置的值可以一次完成,即便是别的线程也正在对其进行访问。如果你不指定 nonatomic ,在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值。
assign
对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char)等等。
此标记说明设置器直接进行赋值,这也是默认值。在使用垃圾收集的应用程序中,如果你要一个属性使用assign,且这个类符合NSCopying协 议,你就要明确指出这个标记,而不是简单地使用默认值,否则的话,你将得到一个编译警告。这再次向编译器说明你确实需要赋值,即使它是 可拷贝的。
retain
对其他NSObject和其子类对参数进行release旧值,再retain新值
指定retain会在赋值时唤醒传入值的retain消息。此属性只能用于Objective-C对象类型,而不能用于Core Foundation对象。(原因很明显,retain会增加对象的引用计数,而基本数据类型或者Core Foundation对象都没有引用计数——译者注)。
注意: 把对象添加到数组中时,引用计数将增加对象的引用次数+1。
copy
对NSString 它指出,在赋值时使用传入值的一份拷贝。拷贝工作由copy方法执行,此属性只对那些实行了NSCopying协议的对象类型有效。更深入的讨论,请参考“复制”部分。
copy与retain:
Copy其实是建立了一个相同的对象,而retain不是:
1.比如一个NSString 对象,地址为0×1111 ,内容为@”STR”,Copy 到另外一个NSString 之后,地址为0×2222 ,内容相同。
2.新的对象retain为1 ,旧有对象没有变化retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1。
总结:retain 是指针拷贝,copy 是内容拷贝。
assign与retain:
1. 接触过C,那么假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块内存的时候会引起程序crash掉。
2. 了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference counting),还是上面的那个例子,我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时引用计数增加到2。这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1。当引用计数变为0的时候,代表该内存不再被任何指针所引用,系统可以把它直接释放掉。
总结:上面两点其实就是assign和retain的区别,assign就是直接赋值,从而可能引起1中的问题,当数据为int, float等原生类型时,可以使用assign。retain就如2中所述,使用了引用计数,retain引起引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。
52,#pragma mark -#pragma mark Initialization含义
它们告诉Xcode编译器,要在编辑器窗格顶部的方法和函数弹出菜单中将代码分隔开;注意 #pragma mark – 的“-”后面不能有空格。如果你的标志没有出现在弹出菜单中,比如没有分隔线出现,请在Xcode菜单 “Preferences..”中的 “Code Sense”选项取消选中”Sort listalphabetically”即可。
53,自定义delegate变量声明时使用assign还是retain?
我们通过发送消息给对象出发特定动作;对象发送某些变化的时候通过回调函数(callback)通知我们。对象在特定事件发生的时候,就会调用对应的回调函数,触发业务逻辑。回调函数通过所谓的代理(Delegation)来实现.
delegate使用方法:
@property (assign) <id>xxxDelegate delegate;
正确的使用方法是使用assign属性而不是retain。之所以对于delegate这类对象使用assign而不是用retain是为了防止循环retain(retain loop)
54,给成员变量(属性)赋值时使不使用self?
使用@property和@synthesize声明一个成员变量,给其赋值是时要在前面加上"self.",以便调用成员变量的setmember方法。直接调用成员变量并且给其赋值:member=[NSString stringWithFormat:@””];将不执行setmember 方法。
使用self调用成员变量并且给其赋值:self.member=[NSString stringWithFormat:@””];将执行setmember方法。
55,如何给UIbutton 同时设置图片(Image)和文字(Title)以及它们的各种状态?
1 startRangeButton = [UIButton buttonWithType:UIButtonTypeCustom]; 2 startRangeButton.frame = CGRectMake(85,componentOriginY, regionImage.size.width, 16); 3 [startRangeButton setBackgroundImage:regionImage forState:UIControlStateNormal]; 4 //还可以设置其高亮状态startRangeButton setBackgroundImage:regionImage forState:UIControlStateHighlighted]; 5 startRangeButton.titleLabel.font = [UIFont systemFontOfSize:7.0]; 6 [startRangeButton setTitle:@"2013-08-01 07:00" forState:UIControlStateNormal]; 7 [startRangeButton setTitleColor:COLOR(101, 199, 240, 1) forState:UIControlStateNormal]; 8 [startRangeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
代码中我设置button背景图片为自己定义的一个regionImage,并设置了button的title = “2013-08-01 07:00”【注意,设置了背景图片后,title只能这样添加,以button.titleLabel.text方式添加会无法显示的】,并且设置了tiitle正常和高亮下文字颜色。
所以看到这里,应该明白button.setBackgroundImage 和 set Image 的区别了吧,前者是可以同时设置文字,后者是一旦设置了image,无法再显示文字。
普通:高亮:
56,如何将NSDate类型转化为距离1970/1/1的毫秒差?
[formatter setDateFormat:@"yyyy-MM-dd HH:mm"]; 这种格式得到的数值是精确到秒的,也就是说少1000,
但是尝试[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];或SS大写,或[formattersetDateFormat:@"yyyy-MM-dd HH:mm.ss.SSS"];都不起作用,最后才发现,原来是这样
NSTimeInterval本身是个秒级别的double类型数值,小数点后面即毫秒数,*1000.0f即可得到毫秒级别的时间差
1 //为了兼容java版本,事件是从1970/1/1开始 2 3 -(NSDate *)getDateTimeFromMilliSeconds:(long long) miliSeconds 4 5 { 6 7 NSTimeInterval tempMilli = miliSeconds; 8 9 NSTimeInterval seconds = tempMilli/1000.0; 10 11 NSLog(@"seconds=%f",seconds); 12 13 return [NSDate dateWithTimeIntervalSince1970:seconds]; 14 15 } 16 17 18 19 //将NSDate类型的时间转换为NSInteger类型,从1970/1/1开始 20 21 -(long long)getDateTimeTOMilliSeconds:(NSDate *)datetime 22 23 { 24 25 NSTimeInterval interval = [datetime timeIntervalSince1970]; 26 27 NSLog(@"interval=%f",interval); 28 29 long long totalMilliseconds = interval*1000 ; 30 31 NSLog(@"totalMilliseconds=%llu",totalMilliseconds); 32 33 return totalMilliseconds; 34 35 }
也就是说,计算结果再自己乘以1000就可以了
1 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 2 [formatter setDateFormat:@"yyyy-MM-dd HH:mm"]; 3 4 NSDate *sDate = [formatter dateFromString:startRangeButton.titleLabel.text]; 5 NSDate *eDate = [formatter dateFromString:endRangeButton.titleLabel.text]; 6 NSTimeInterval sinterval = [sDate timeIntervalSince1970]; 7 long long start = sinterval*1000; 8 NSTimeInterval einterval = [eDate timeIntervalSince1970]; 9 long long end = einterval*1000; 10 [mConnectionHelper doTrack:mobile startTime:start endTime:end];
57,ios中的全局静态变量
Objective-C 支持全局变量
主要有两种实现方式:
(1)第一种和C/C++中的一样, 使用"extern"关键词;
(2)另外一种就是使用单例实现。
(比如我们经常会把一个变量放在AppDelegate里面作为全局变量来访问, 其中AppDelegate就是一个单例类)
在Objective-C中如何实现像C++中那样的静态成员变量呢?
你需要做的是在一个类A的implementation(.m或者.mm)文件中定义一个static变量,然后为A类定义静态成员函数(class method,也就是类方法)来操作该变量。
1 //example.h 2 @interface Example : NSObject { 3 4 } 5 - (id)init; 6 +(int)instanceCount; 7 @end
1 //example.m 2 #import "example.h" 3 static int count; 4 @implementation Example 5 -(id)init{ 6 self = [super init]; 7 if(nil!=self){ 8 count+=1; 9 } 10 return self; 11 } 12 +(int)instanceCount{ 13 return count; 14 } 15 @end
上面的例子中你就可以通过[Example instanceCount]对静态变量count进行访问,无须创建实例。
警告: static 写在interface外面编译是没有错误的,但是编译器会报警告,这么说这样的写法是不被编辑器认可的。
错误:static 写在interface里面会直接报错,显然这样的语法是不被认可的。
static关键字声明的变量必须放在implementation外面,或者方法中,如果不为它赋值默认为0,
它只在程序开机初始化一次。
58,如何使用 NSNotificationCenter 在viewcontroller之间进行传值?
简单点的来,两个界面间传值,直接上代码了:
sendViewcontroller.m
1 //SettingViewController :接受值的viewcontroller 2 SettingViewController *setting = [[SettingViewController alloc] init]; 3 [[NSNotificationCenter defaultCenter] addObserver:setting selector:@selector(received:) name:@"msetting" object:nil]; 4 NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:@"user",@"type", nil]; 5 6 [[NSNotificationCenter defaultCenter] postNotificationName:@"msetting" object:dict]; 7 [self.navigationController pushViewController:setting animated:YES]; 8 9 [setting release]; 10 SettingViewController.m(接收值的viewcontroller)
1 -(void)received:(NSNotification *)notification{ 2 3 id data = [notification object]; 4 NSLog(@"received data: %@",data); 5 }
这样就实现了基本的使用,跟delegate类似,注意 addObserver时,需要写目标viewcontroller的实例,而不是self。
59,Thread EXC_BAD_ACCESS : objc_retain, objc_getProperty 崩溃错误
如上图所示,遇到这个错误,从字面的意思我们大致能猜到,是有属性已经被release掉了,但是我们又使用它了,所以,一部一部排查把,一定有某个地方的属性提前被release掉了,自己手动管理内存就会有这样的困恼,代码很多,不想去找,一定要有耐心,找的过程还可以学到很多知识。
如上图,这个就是我找到的原因所在,unarchiver release掉了,而我们在其它的类中想使用location的属性。
60,MAC 终端(bash)svn命令不识别 command not found
在mac os 10.8中,svn Command line tools是没有自动安装的,这样的话,svn 命令行就会失效,解决办法:
1.打开xcode偏好设置(comand+,)-->"Download" -->Components:
2.点击“Command line tools”下载,下载完成之后安装。
3.安装完成之后,打开终端,输入“svn help”,如果出现如下所示,说明命令行工具安装好了。
61,ios MapKit 判断坐标是否在MapView显示范围内
1 CLLocationDegrees leftDegrees = mapView.region.center.longitude –(mapView.region.span.longitudeDelta / 2.0); 2 CLLocationDegrees rightDegrees = mapView.region.center.longitude +(mapView.region.span.longitudeDelta / 2.0); 3 CLLocationDegrees bottomDegrees = mapView.region.center.latitude –(mapView.region.span.latitudeDelta / 2.0); 4 CLLocationDegrees topDegrees = self.region.center.latitude +(mapView.region.span.latitudeDelta / 2.0); 5 if (leftDegrees > rightDegrees) { // Int‘l Date Line in View 6 leftDegrees = -180.0 - leftDegrees; 7 if (coords.longitude > 0) // coords to West of Date Line 8 coords.longitude = -180.0 - coords.longitude; 9 } 10 If (leftDegrees <= coords.longitude && coords.longitude <= rightDegrees && bottomDegrees <= coords.latitude && coords.latitude <= topDegrees) { 11 // 坐标在范围内 12 }
62,在App图标上显示数字徽标
IOS7 :
1 UIApplication *app = [UIApplication sharedApplication]; 2 3 // 应用程序右上角数字 4 app.applicationIconBadgeNumber = 99;
上面的代码可以搞定
IOS8:
iOS8中设置application badge value 会抛错:Attempting to badge the application icon but haven‘t received permission from the user to badge the
原因是因为在ios8中,设置应用的application badge value需要得到用户的许可。使用如下方法咨询用户是否许可应用设置application badge value
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
在这之前要判断系统是否为iOS8的系统,否则8之前的系统会报错。
1 UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil]; 2 3 [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; 4 5 UIApplication *app = [UIApplication sharedApplication]; 6 // 应用程序右上角数字 7 app.applicationIconBadgeNumber = 10;
注意:清除数字请将数字设置为 0