XCODE
Table of Contents
- 1. 关于xib
- 2. Xcode 调试
- 3. ios 10.8 xcode 4.5 添加的view 默认是iphone样式。
- 4. ios6 之后添加了 auto layout 功能。 需要关闭的时候可以如下操作
- 5. 编程技巧
- 6. 获取IOS设备的类型和系统版本
- 7. iOS学习笔记——字符串编码转换
- 8. 造成unrecognized selector sent to instance……程序崩溃原因分析
- 9. 如何将NSstring转欢成char (UTF8String, cString)
- 10. Cocoa Fundation内存释放原则
- 11. iOS中NSString引用计数内存管理机制分析
- 12. iOS中的堆(heap)和栈(stack)的理解
- 13. 删除视图中的子视图
- 14. iPhone 程式要間隔一段時間執行某個函式的方法
- 15. 设置UIPickerView默认选择
- 16. UIView
- 17. iOS Programming – 触摸事件处理
- 18. 遇到的问题
- 19. Xcode文件读写
- 20. 取得wifi名称
- 21. 多线程
- 22. NSDate
- 23. Xcode 获取私有API
- 24. xcode的MapKit中,如何点击大头针的时候,出现自定义的“callout bubble”
- 25. xcode如何修改uitabbaritem的字体颜色
- 26. Xcode快捷键
- 27. 如何清除xcode里面的mobileprovision文件
- 28. GCD
1 关于xib
用xib文件添加视图的时候,在4.2版本的xcode中,程序会报错。需要把view按住control键拖到文件里面。生成一下自动代码,并删除自动代码之后就正常了。
1.1 Xcode4.2
Xcode4.2 中清理xib缓存
- option + product menu -> Clean Build Folder
- iOS Simulator -> Reset Content and settings
2 Xcode 调试
在project-setting中找到 “Run Static Analyzer” 键,然后把值修改为“YES”.这样在编码的时候,xcode就可以自动为我们检查内存泄露了
3 ios 10.8 xcode 4.5 添加的view 默认是iphone样式。
可以在选中view之后,选择attributes inspector –> size。 可以改变样式。
4 ios6 之后添加了 auto layout 功能。 需要关闭的时候可以如下操作
使用Xcode 4.5 创建App时,Auto Layout功能在所有nib或Storyboard 文件中,默认是enable(开启的) 需要关闭storyboard或xib界面文件的Use Auto Layout 选项,这是因为Auto Layout特性是iOS 6 新增加的,在之前的 5.0/5.1 Simulator模拟器中不支持。 1 open user interface document 2 choose view –> Utilities –> show file inspector –> interface Builder Document 下。 uncheck “use auto layout".
5 编程技巧
5.1 点击界面空白出隐藏keyboard。 也可以做其他事情。
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; [name resignFirstResponder]; [password resignFirstResponder]; }
5.2 TextField 输入完毕后 隐藏 keyboard
实现textField 的 didEndonExit 事件。在方法里面写上
[textfiel resignFirstResponder];
5.3 使控件不可用
设置控件的 userinterfaceEnabled
[control setUserInteractionEnabled:YES];
5.4 xcode 调试 EXCBADACCESS
- 第一种方法:在程序 crash 之后,在控制台输入 bt,就可以显示 crash 堆栈:
- 为工程运行时加入 NSZombieEnabled、 MallocStackLogging环境变量,并设为启用。 produce–>edit schema–>run (environment variables)中
- MallocStackLogging 启用
- 为工程运行时加入 NSZombieEnabled 环境变量,并设为启用。
6 获取IOS设备的类型和系统版本
// DeviceHelper.m // DeviceUtil // // Created by LUOYL on 12-4-9. // Copyright (c) 2012年 http://luoyl.info. All rights reserved. // #import "DeviceHelper.h" #import "sys/utsname.h" @implementation DeviceHelper /* *功能:获取设备类型 * * AppleTV2,1 AppleTV(2G) * i386 simulator * * iPod1,1 iPodTouch(1G) * iPod2,1 iPodTouch(2G) * iPod3,1 iPodTouch(3G) * iPod4,1 iPodTouch(4G) * * iPhone1,1 iPhone * iPhone1,2 iPhone 3G * iPhone2,1 iPhone 3GS * * iPhone3,1 iPhone 4 * iPhone3,3 iPhone4 CDMA版(iPhone4(vz)) * iPhone4,1 iPhone 4S * * iPad1,1 iPad * iPad2,1 iPad2 Wifi版 * iPad2,2 iPad2 GSM3G版 * iPad2,3 iPad2 CDMA3G版 * @return null */ + (NSString *)getDeviceVersion { struct utsname systemInfo; uname(&systemInfo); //get the device model and the system version NSString *machine =[NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; return machine; } /** 获取IOS系统的版本号 */ + (NSString*)getOSVersion { return [[UIDevice currentDevice]systemVersion]; } /** 判断当前设备是否ipad */ + (BOOL)isIpad { return [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad; } /** 判断当前设备是否iphone */ + (BOOL)isIphone { return [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone; } /** 判断当前系统是否有摄像头 */ + (BOOL)hasCamera { return [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]; } @end
7 iOS学习笔记——字符串编码转换
我们知道,使用NSURLConnection的代理方法下载网页,存到一个NSData中,
NSMutableData *pageData; [pageData appendData:data];
如果网页编码是UTF-8的,可以这么转换为字符串:
NSString *pageSource = [[NSString alloc] initWithData:pageData encoding:NSUTF8StringEncoding];
如果网页是gbk(或者gb2312),用UTF8转换的话,pageSource返回nil。这时需要使用gbk编码做转换,但是NSStringEncoding不含gbk,怎么办?用另一个方法处理一下:
NSStringEncoding gbkEncoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); NSString *pageSource = [[NSString alloc] initWithData:pageData encoding:gbkEncoding];
为什么可以这么处理?在NSString.h(按住command,双击NSStringEncoding即能查看),对NSStringEncoding的定义中,注释这么写着:
Note that in addition to the values explicitly listed below, NSStringEncoding supports encodings provided by CFString.
See CFStringEncodingExt.h for a list of these encodings.
See CFString.h for functions which convert between NSStringEncoding and CFStringEncoding.
8 造成unrecognized selector sent to instance……程序崩溃原因分析
造成unrecognized selector sent to instance……,大部分情况下是因为对象被提前release了,在你心里不希望他release的情况下,指针还在,对象已经不在了。 很多时候,是因为init初始化函数中,对属性赋值没有使用self.foo赋值,而是直接对foo赋值,导致属性对象没有retain(心里以为retain了),而提前释放。
属性必须用 self
属性必须用 self 属性必须用 self 属性必须用 self 属性必须用 self 属性必须用 self 属性必须用 self 属性必须用 self 属性必须用 self 属性必须用 self
=====
9 如何将NSstring转欢成char (UTF8String, cString)
如果是 .m文件,直接可以转换
char *s; NSString *str; s=[str UTF8String]; str=[NSString stringWithUTF8String:s]; str=[NSString stringWithFormat:@"%s",s];
如果是.mm会提示出错,因为[str UTF8String]返回的是const char *
10 Cocoa Fundation内存释放原则
- 通过分配或复制创建的对象保持计数1
- 假设任何别的方法获取的对象保持计数1,而且在自动释放池中. 要想在当前执行范围外使用该对象,就必须保持它
- 向集合添加对象时它就被保持,从集合移除对象时就被释放.释放集合对象会释放该集合中的所有对象
- 确保有多少alloc,copy,mutableCopy或retain消息就有多少release或autorelease消息发送给该对象. 换句话说,确保你的代码平衡
- 在访问方法设置属性,先保持,再释放 (ztime: 现在有@propperty , @synthesize 两个指令自动创建此代码)
- 用@"…"结构创建的NSString对象是常量.发送release或retain并无效果
11 iOS中NSString引用计数内存管理机制分析
在 iOS 中引用计数是内存的管理方式,虽然在 iOS5 版本中,已经支持了自动引用计数管理模式,但理解它的运行方式有助于我们了解程序的运行原理,有助于 debug 程序。 操作系统的内存管理分成堆和栈。
在堆中分配的内存,都试用引用计数模式;在栈中则不是。
NSString 定义的对象是保存在栈中,所以它没有引用计算。看一些书上说它的引用计算会是 fffffffff 最大整数,测试的结果显示它是- 1. 对该对象进行 retain 操作,不好改变它的 retainCount 值。
MutableNSString 定义的对象,需要先分配堆中的内存空间,再初始化才能使用。它是采用引用计数管理内存的。对该对象做 retainCount 操作则每次增加一个。
NSString: initWithString NSString: stringWithString 是在栈上分配的空间。没有引用计数。 NSString: initWithFormat NSString: stringWithFormat 是在堆上分配的空间,有引用计数。
不论在堆上还是在栈上分配空间的NSString, 在str = [str substringFromIndex:2];之后,都会在堆上分配一个新的空间。str会指向新的内存空间。有可能会造成内存泄露。所以应该 str1 = [str substringFromIndex:2]; [str release]; str = str1;
// 下面的内容说的不正确。 其实,引用计数是对内存区域的空间管理方式,是应从内存块的视角去看的。任何对象都是指向它的指针,有多少个指针指向它,就有多少个引用计算。 如果没有任何指针指向该内存块了,很明显,该内存块就没有对象引用了,引用计算就是 0, 系统会人为该内存区域已经空闲,于是立即清理,也就是更新一下管理堆的链表中某个标示位。 // 到此为止
12 iOS中的堆(heap)和栈(stack)的理解
操作系统iOS 中应用程序使用的计算机内存不是统一分配空间,运行代码使用的空间在三个不同的内存区域,分成三个段:“text segment “,“stack segment ”,“heap segment ”。
段“text segment ”是应用程序运行时应用程序代码存在的内存段。每一个指令,每一个单个函数、过程、方法和执行代码都存在这个内存段中直到应用程序退出。一般情况下,你不会真的不得不知道这个段的任何事情。 当应用开始以后,函数main() 被调用,一些空间分配在”stack” 中。这是为应用分配的另一个段的内存空间,这是为了函数变量存储需要而分配的内存。每一次在应用中调用一个函数,“stack ”的一部分会被分配在”stack” 中,称之为”frame” 。新函数的本地变量分配在这里。 正如名称所示,“stack ”是后进先出(LIFO )结构。当函数调用其他的函数时,“stack frame ”会被创建;当其他函数退出后,这个“frame ”会自动被破坏。 “heap” 段也称为”data” 段,提供一个保存中介贯穿函数的执行过程,全局和静态变量保存在“heap ”中,直到应用退出。 为了访问你创建在heap 中的数据,你最少要求有一个保存在stack 中的指针,因为你的CPU 通过stack 中的指针访问heap 中的数据。 你可以认为stack 中的一个指针仅仅是一个整型变量,保存了heap 中特定内存地址的数据。实际上,它有一点点复杂,但这是它的基本结构。
简而言之,操作系统使用stack 段中的指针值访问heap 段中的对象。如果stack 对象的指针没有了,则heap 中的对象就不能访问。这也是内存泄露的原因。 在iOS 操作系统的stack 段和heap 段中,你都可以创建数据对象。 stack 对象的优点主要有两点,一是创建速度快,二是管理简单,它有严格的生命周期。stack 对象的缺点是它不灵活。创建时长度是多大就一直是多大,创建时是哪个函数创建的,它的owner 就一直是它。不像heap 对象那样有多个owner ,其实多个owner 等同于引用计数。只有heap 对象才是采用“引用计数”方法管理它。 stack 对象的创建 只要栈的剩余空间大于stack 对象申请创建的空间,操作系统就会为程序提供这段内存空间,否则将报异常提示栈溢出。 heap 对象的创建 操作系统对于内存heap 段是采用链表进行管理的。操作系统有一个记录空闲内存地址的链表,当收到程序的申请时,会遍历链表,寻找第一个空间大于所申请的heap 节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序。 例如: NSString 的对象就是stack 中的对象,NSMutableString 的对象就是heap 中的对象。前者创建时分配的内存长度固定且不可修改;后者是分配内存长度是可变的,可有多个owner, 适用于计数管理内存管理模式。 两类对象的创建方法也不同,前者直接创建“NSString * str1=@"welcome"; “,而后者需要先分配再初始化“ NSMutableString * mstr1=[[NSMutableString alloc] initWithString:@"welcome"]; ”。
(miki西游 @mikixiyou 原文链接: http://mikixiyou.iteye.com/blog/1595230 )
再补充一点,这里说的是操作系统的堆和栈。 在我们学习“数据结构”时,接触到的堆和栈的概念和这个操作系统中的堆和栈不是一回事的。 操作系统的堆和栈是指对内存进行操作和管理的一些方式。 “数据结构“的堆实际上指的就是(满足堆性质的)优先Queue 的一种数据结构,第1 个元素有最高的优先权;栈实际上就是满足先进后出的性质的数据或数据结构。
13 删除视图中的子视图
for (UIView *oneView in cell.subviews ) { if ([oneView isKindOfClass:[UILabel class]]) { [oneView removeFromSuperview]; } }
=====
14 iPhone 程式要間隔一段時間執行某個函式的方法
最基本的就是用NSTimer .. 只是這個要建一個 NSTimer 再做一些設定.. 感覺有點麻煩..
有看到另一種方法. [self performSelector:@selector(test:) withObject:nnil afterDelay:1.0];
可以設定過幾秒後執行. 要一直執行就在函式中也加上同樣命令.就會一直進去了. 要停止的話就做判斷,條件達到的時候不會跑該命令就好.
另外在cocos2D裡也有
[self schedule:@selector(objMove:) interval:0.01f]; 的方式可以達成. 不過這個跟 performSelector:(selector)… 方法有點不一樣. 就是 schedule 比較像timer 會一直執行.. (其實裡面好像就是幫你處理timer的宣告..) 所以要停止的話要用 [self unschedule:@selector(objMove:)];
來停止這個動作的繼續執行.
=====
15 设置UIPickerView默认选择
#+beginsrc objc [[self pickerView] selectRow:3 inComponent:0 animated:NO]; #+endsrc objc
16 UIView
16.1 UIView层次管理 放到最上层 放到最下层
将一个UIView显示在最前面只需要调用其父视图的 bringSubviewToFront()方法。 将一个UIView层推送到背后只需要调用其父视图的 sendSubviewToBack()方法。
16.2 UIView如何管理子视图
UIView提供了很多建立和管理视图的方法。
- 添加视图
insertSubview:atIndex: //放在子视图数组的具体索引位置
insertSubview:aboveSubview: //某个子视图前面
insertSubview:aboveSubview: //某个子视图前面
- 重新排序和删除子视图
[parentView exchangeSubviewAtIndex:i withSubviewAtIndex:j]//交换两个视图的位置
bringSubviewToFront:和sendSubviewToBack://将子视图提前活置后
[childView removeSuperview]//删除某个视图的子视图
- 视图回调
某个视图的层次一改变,该视图就会收到一次回调。
- 调用addSubivew:成功后会给该视图发送didAddSubivew:回调,触发UIView的子类在心增视图时执行其他操作。
- ndidMoveToSuperview:会通知相关视图他们的上级视图已经变化。
- 视图移动前会发出willMoveToSuperview:回调
- didMoveToWindow:回调和didMoveToSuperview:相似,从命名上能看出其区别。
- willMoveToWindow:在视图移动前发出的回调。
- willRemoveToSubview:回调通知父视图子视图即将被删除
//当加入视图完成后调用 (void)didAddSubview:(UIView *)subview //当视图移动完成后调用 (void)didMoveToSuperview //当视图移动到新的WINDOW后调用 (void)didMoveToWindow //在删除视图之后调用 (void)willRemoveSubview:(UIView *)subview //当移动视图之前调用 (void)didMoveToSuperview:(UIView *)subview //当视图移动到WINDOW之前调用 (void)didMoveToWindow
- 管理视图
//加一个视图到一个视图里面 addSubview: //将一个视图移到前面 bringSubviewToFront: //将一个视图推送到背后 sendSubviewToBack: //把视图移除 removeFromSuperview //插入视图 并指定索引 insertSubview:atIndex: //插入视图在某个视图之上 insertSubview:aboveSubview: //插入视图在某个视图之下 insertSubview:belowSubview: //交换两个位置索引的视图 exchangeSubviewAtIndex:withSubviewAtIndex:
- 找出所有父视图
// Return an array of parent views from the window down to the view NSArray *pathToView(UIView *aView) { NSMutableArray *array = [NSMutableArray arrayWithObject:aView]; UIView *view = aView; UIWindow *window = aView.window; while (view != window) { view = [view superview]; [array insertObject:view atIndex:0]; } return array; }
- 找出所有子视图
NSArray *allSubviews(UIView *aView) { NSArray *results = [aView subviews]; for (UIView *eachView in [aView subviews]) { NSArray *riz = allSubviews(eachView); if (riz) { results = [results arrayByAddingObjectsFromArray:riz]; } } return results; }
- 返回Application中的所有视图
// Return all views throughout the application NSArray *allApplicationViews() { NSArray *results = [[UIApplication sharedApplication] windows]; for (UIWindow *window in [[UIApplication sharedApplication] windows]) { NSArray *riz = allSubviews(window); if (riz) results = [results arrayByAddingObjectsFromArray: riz]; } return results; }
- 建立UIView
CGContextRef context = UIGraphicsGetCurrentContext(); //标记动画开始 [UIView beginAnimations:nil context:context]; //定义动画加速或减速的方式 [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; //定义动画的时长 1秒 [UIView setAnimationDuration:1.0]; //中间处理 位置变化,大小变化,旋转,等等的 [[self.view viewWithTag:999] setAlpha:1.0f]; //标志动画块结束 [UIView commitAnimations]; //还可以设置回调 [UIView setAnimationDelegate:self]; //设置回调调用的方法 [UIView setAnimationDidStopSelector:@selector(animationFinished:)];
UIView掌管直接屏幕绘图。他的drawRect:方法提供一种低级方式来直接绘制内容,允许使用Quartz 2D调用创建和显示任意元素,可将这两个元素结合起来共同构建具体、可操作的界面。
当用户触摸屏幕时,Touchview类收集一系列点,在每个触摸移动之处,touchesMoved:WithEvent:方法调用setNeedsDisplay。这又会触发对drawRect:方法的调用,其中视图将这些点绘制成线段来创建一个可视屏幕路径。
17 iOS Programming – 触摸事件处理
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
当手指接触屏幕时,就会调用touchesBegan:withEvent方法; 当手指在屏幕上移时,动就会调用touchesMoved:withEvent方法; 当手指离开屏幕时,就会调用touchesEnded:withEvent方法; 当触摸被取消(比如触摸过程中被来电打断),就会调用touchesCancelled:withEvent方法。而这几个方法被调用时,正好对应了UITouch类中phase属性的4个枚举值。
[self.nextResponder touchesBegan:touches withEvent:event]; 可以把事件传递到下一个相应事件的view。
18 遇到的问题
18.1 uinavigationController pushviewController 的时候是不是需要把 push的viewcontroller给release掉。
答案是需要。因为push会retain。 但当时的情况是 release 这个push 的viewcontroller会导致execbadaccess错误。
原因是在这个被push的viewcontroller中,有些不需要release的view或button、label之类的控件被release掉了。 并且没有实现dealloc 方法。
autorelease的不需要手动release。
dealloc方法中要写上 [super dealloc]。会自动释放标记为autorelease的控件。
18.2 incomplete implementation
这个一般来说是在.h文件中声明了。却没有在.m文件中实现方法。
19 Xcode文件读写
- 得到文件路径。
NSArray *path = NSSearchPathForDirectorisInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *PathDir = [path objectAtIndex:0]; //NSDocumentDirectory 是 NSSearchPathDirectory的枚举。可以得到其他文件夹路径。 //文件夹追加文件名称。 NSString *pathFile = [PathDir stringByAppendingFormat:@"/DataFile.plist"]; //记得添加 "/"
20 取得wifi名称
需要添加SystemConfiguration.framework #+beginsrc objc CFArrayRef arrayRef = CNCopySupportedInterfaces(); NSArray *interfaces = (NSArray *)arrayRef; NSLog(@"interfaces -> %@",interfaces);
NSLog(@"%lu",(unsigned long)interfaces.count);
for (NSString *interfaceName in interfaces) { NSLog(@"%@",interfaceName); CFDictionaryRef dictRef = CNCopyCurrentNetworkInfo((CFStringRef)interfaceName); NSLog(@"%@",dictRef); if (dictRef != NULL) { NSDictionary *networkInfo = (NSDictionary *)dictRef; NSLog(@"network info -> %@",networkInfo); CFRelease(dictRef); } }
CFRelease(arrayRef);
#+endsrc objc
21 多线程
线程创建与启动 NSThread的创建主要有两种直接方式: [NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil]; 和 NSThread* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(myThreadMainMethod:) object:nil]; [myThread start]; 这两种方式的区别是:前一种一调用就会立即创建一个线程来做事情;而后一种虽然你 alloc 了也 init了,但是要直到我们手动调用 start 启动线程时才会真正去创建线程。这种延迟实现思想在很多跟资源相关的地方都有用到。后一种方式我们还可以在启动线程之前,对线程进行配置,比如设置 stack 大小,线程优先级。 还有一种间接的方式,更加方便,我们甚至不需要显式编写 NSThread 相关代码。那就是利用 NSObject 的类方法 performSelectorInBackground:withObject: 来创建一个线程: [myObj performSelectorInBackground:@selector(myThreadMainMethod) withObject:nil]; 其效果与 NSThread 的 detachNewThreadSelector:toTarget:withObject: 是一样的。
线程停止 使用 [thread cancel];
线程执行的效果,需要线程启动的函数执行完毕之后才能体现出来。如果线程启动一个while(1)循环,那么基本就废了,在界面就不能体现线程都效果了。
22 NSDate
22.1 得到当前日期的前一天或前几天是什么日期
- 首先组织一个字符串20000101或20010101之类。
- 用NSDateFormatter转换成NSDate格式
#+beginsrc objc NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; NSTimeZone *timeZone = [NSTimeZone localTimeZone]; //得设置一下时区 [formatter setTimeZone:timeZone]; [formatter setDateFormat : @"M/d/yyyy h:m a"];
NSString *stringTime = @"12/5/2011 3:4 am";
NSDate *dateTime = [formatter dateFromString:stringTime];
NSDate *preDate = [NSDate dateWithTimeInterval:-24*60*60*10 sinceDate:dateTime]; //-24*60*60*10 是10天的秒数。所以preDate就是2011年11月5日的10天前的日期。 #+endsrc objc
- 也可以直接得到当前日期,
#+beginsrc objc NSDate *date = [NSDate date]; //可以得到当前日期。 NSDate *preDate = [NSDate dateWithTimeInterval:-24*60*60*10 sinceDate:date]; #+endsrc objc
22.2 得到当前月份有几天
#+beginsrc objc NSCalendar *calendar = [NSCalendar currentCalendar]; unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *components = [calendar components:unitFlags fromDate:[NSDate date]];
NSInteger iCurYear = [components year]; //当前的年份
NSInteger iCurMonth = [components month]; //当前的月份
NSInteger iCurDay = [components day]; // 当前的号数
#+endsrc objc
22.3 NSDate 与 NSString 互换
#+beginsrc objc
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; NSTimeZone *timeZone = [NSTimeZone localTimeZone];
[formatter setTimeZone:timeZone]; [formatter setDateFormat : @"M/d/yyyy h:m a"];
NSString *stringTime = @"12/5/2011 3:4 am";
NSDate *dateTime = [formatter dateFromString:stringTime];
NSLog(@"%@", dateTime);//打印2011-12-04 19:04:00 +0000,这里+0000表示时区
NSDate *dateNow = [NSDate date];
NSLog(@"%@", dateNow);//打印2011-08-17 08:26:57 +0000,这里+0000表示时区
[formatter setDateFormat : @"yyyy年M月d日 H点m分"];
NSLog(@"%@", [formatter stringFromDate:dateNow]);//打印2011年8月17日 16点26分 #+endsrc objc
23 Xcode 获取私有API
- 首先要下载class-dump.
class-dump下载地址http://www.codethecode.com/projects/class-dump/
- 然后下载DumpFrameworks.pl
DumpFrameworks.pl的下载地址:https://github.com/shuhongwu/HackSpringDemo/blob/master/DumpFrameworks.pl
- 把class-dump放到$PATH路径下
- DumpFrameworks.pl中的ios库的路径有可能不对,需要手动修改。
- 然后执行DumpFrameworks.pl即可,头文件会放到 $HOME/Headers 目录下
- 将想用的头文件,组成xxx.framework/Headers的样式。导入工程。
但是bulidsetting 设置framework的search path 时要设置真实的私有库路径,因为我们要用它的可执行文件,只有头文件是不行的。
例如:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/PrivateFrameworks
这样就可以调用ios的私有库了
24 xcode的MapKit中,如何点击大头针的时候,出现自定义的“callout bubble”
大头针是一个MKAnnotationView ( MKPinAnnotationView) callout bubble 也是一个MKAnnotationView
MKAnnotationView都有一个annotation 大概的方法是,
- 先创建MKAnnotation的子类
@interface customMKAnnotation : NSObject 然后声明“customMKAnnotation 遵守 MKAnnotation协议 变为 @interfact customMKAnnotation : NSObject < MKAnnotation>
此 子类 中一般定义一个type变量,
- 创建自定义的MKAnnotationView的子类。
然后在主程序中定义一个customMKAnnotation的实例,type值为“1”
在程序运行时,往mapView中添加普通的customMKAnnotation实例(type值为“2”)。
点击这些type值为“2”的annotation,会触发didSelectAnnotationView方法。在此函数中根据点击的annotation的坐标,把此坐标赋值给type值为“1”的实例。并添加此实例到mapView中。
添加annotation到mapview中会触发viewForAnnotation方法。在此函数中,根据type的值来区别,是创建普通的MKAnnotationView还是特殊的。
写了半天,还是没办法把语言组织清楚。疯了,还在看代码把,回头把代码上传到git。
25 xcode如何修改uitabbaritem的字体颜色
[self.tabBarItem setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor redColor], UITextAttributeTextColor, nil] forState:UIControlStateNormal];
把此代码放到uiView的[viewDidAppear]和[viewDidDisAppear]里面。
26 Xcode快捷键
26.1 代码格式化
Xcode 版本:4.2和4.2之前的版本 选中需要格式化代码 -> Edit -> Format ->Re-Indent Xcode 版本:4.2之后的版本 选中需要格式化代码 -> Editor -> Structure ->Re-Indent 或者 选中需要格式化代码 -> 右击 ->选中 Structure ->Re-Indent command + ']': 代码块 右移 command + '[': 代码块 左移
27 如何清除xcode里面的mobileprovision文件
首先cd到目录“~/Library/MobileDevice/Provisioning\ Profiles” 然后删除里面所有的mobileprovision文件
cd ~/Library/MobileDevice/Provisioning\ Profiles/ rm *.mobileprovision
这样再看xcode的时候,所有的mobileprovision,发现没有任何provisioning profile了。这个时候不需要再次的去一个一个的添加。
访问XCode的Preferences>Accounts,在Apple IDs里面找到你的帐号,选中后,在右侧,在Name下面会有一行描述。双击。在弹出窗口里面,有个刷新按钮,点击之后,属于这个帐号的provisioning profile就会再次出现
28 GCD
什么是GCD Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术,它看起来象就其它语言的闭包(Closure)一样,但苹果把它叫做blocks。
应用举例 让我们来看一个编程场景。我们要在iphone上做一个下载网页的功能,该功能非常简单,就是在iphone上放置一个按钮,点击该按钮时,显示一个转动的圆圈,表示正在进行下载,下载完成之后,将内容加载到界面上的一个文本控件中。
不用GCD前 虽然功能简单,但是我们必须把下载过程放到后台线程中,否则会阻塞UI线程显示。所以,如果不用GCD, 我们需要写如下3个方法:
someClick 方法是点击按钮后的代码,可以看到我们用NSInvocationOperation建了一个后台线程,并且放到NSOperationQueue中。后台线程执行download方法。 download 方法处理下载网页的逻辑。下载完成后用performSelectorOnMainThread执行downloadcompleted 方法。 downloadcompleted 进行clear up的工作,并把下载的内容显示到文本控件中。 这3个方法的代码如下。可以看到,虽然 开始下载 -> 下载中 -> 下载完成 这3个步骤是整个功能的三步。但是它们却被切分成了3块。他们之间因为是3个方法,所以还需要传递数据参数。如果是复杂的应用,数据参数很可能就不象本例子中的NSString那么简单了,另外,下载可能放到Model的类中来做,而界面的控制放到View Controller层来做,这使得本来就分开的代码变得更加散落。代码的可读性大大降低。
static NSOperationQueue * queue; - (IBAction)someClick:(id)sender { self.indicator.hidden = NO; [self.indicator startAnimating]; queue = [[NSOperationQueue alloc] init]; NSInvocationOperation * op = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil] autorelease]; [queue addOperation:op]; } - (void)download { NSURL * url = [NSURL URLWithString:@"http://www.youdao.com"]; NSError * error; NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error]; if (data != nil) { [self performSelectorOnMainThread:@selector(download_completed:) withObject:data waitUntilDone:NO]; } else { NSLog(@"error when download:%@", error); [queue release]; } } - (void) download_completed:(NSString *) data { NSLog(@"call back"); [self.indicator stopAnimating]; self.indicator.hidden = YES; self.content.text = data; [queue release]; }
使用GCD后 如果使用GCD,以上3个方法都可以放到一起,如下所示:
// 原代码块一 self.indicator.hidden = NO; [self.indicator startAnimating]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 原代码块二 NSURL * url = [NSURL URLWithString:@"http://www.youdao.com"]; NSError * error; NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error]; if (data != nil) { // 原代码块三 dispatch_async(dispatch_get_main_queue(), ^{ [self.indicator stopAnimating]; self.indicator.hidden = YES; self.content.text = data; }); } else { NSLog(@"error when download:%@", error); } });
首先我们可以看到,代码变短了。因为少了原来3个方法的定义,也少了相互之间需要传递的变量的封装。
另外,代码变清楚了,虽然是异步的代码,但是它们被GCD合理的整合在一起,逻辑非常清晰。如果应用上MVC模式,我们也可以将View Controller层的回调函数用GCD的方式传递给Modal层,这相比以前用@selector的方式,代码的逻辑关系会更加清楚。
GCD的定义 简单GCD的定义有点象函数指针,差别是用 ^ 替代了函数指针的 * 号,如下所示:
// 申明变量 (void) (loggerBlock)(void); // 定义 loggerBlock = ^{ NSLog(@"Hello world"); }; // 调用 loggerBlock(); 但是大多数时候,我们通常使用内联的方式来定义它,即将它的程序块写在调用的函数里面,例如这样:
dispatchasync(dispatchgetglobalqueue(0, 0), ^{ // something }); 从上面大家可以看出,block有如下特点:
程序块可以在代码中以内联的方式来定义。 程序块可以访问在创建它的范围内的可用的变量。 系统提供的dispatch方法 为了方便地使用GCD,苹果提供了一些方法方便我们将block放在主线程 或 后台线程执行,或者延后执行。使用的例子如下:
// 后台执行: dispatch_async(dispatch_get_global_queue(0, 0), ^{ // something }); // 主线程执行: dispatch_async(dispatch_get_main_queue(), ^{ // something }); // 一次性执行: static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // code to be executed once }); // 延迟2秒执行: double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // code to be executed on the main queue after delay }); dispatch_queue_t 也可以自己定义,如要要自定义queue,可以用dispatch_queue_create方法,示例如下: dispatch_queue_t urls_queue = dispatch_queue_create("blog.devtang.com", NULL); dispatch_async(urls_queue, ^{ // your code }); dispatch_release(urls_queue);
另外,GCD还有一些高级用法,例如让后台2个线程并行执行,然后等2个线程都结束后,再汇总执行结果。这个可以用dispatchgroup, dispatchgroupasync 和 dispatchgroupnotify来实现,示例如下:
dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ // 并行执行的线程一 }); dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{ // 并行执行的线程二 }); dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{ // 汇总结果 });
修改block之外的变量 默认情况下,在程序块中访问的外部变量是复制过去的,即写操作不对原变量生效。但是你可以加上 _block来让其写操作生效,示例代码如下:
_block int a = 0; void (foo)(void) = ^{ a = 1; } foo(); // 这里,a的值被修改为1 后台运行 GCD的另一个用处是可以让程序在后台较长久的运行。在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。
让程序在后台长久运行的示例代码如下:
// AppDelegate.h文件 @property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask; // AppDelegate.m文件 - (void)applicationDidEnterBackground:(UIApplication *)application { [self beingBackgroundUpdateTask]; // 在这里加上你需要长久运行的代码 [self endBackgroundUpdateTask]; } - (void)beingBackgroundUpdateTask { self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [self endBackgroundUpdateTask]; }]; } - (void)endBackgroundUpdateTask { [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask]; self.backgroundUpdateTask = UIBackgroundTaskInvalid; }
总结 总体来说,GCD能够极大地方便开发者进行多线程编程。如果你的app不需要支持iOS4.0以下的系统,那么就应该尽量使用GCD来处理后台线程和UI线程的交互。 >>>>>>> 5ad26efa05b7e6a56245672392a978c418af053e