iOS--Quartz 2D
为了在一个ios应用上面绘制,应该先建立一个UIView对象,然后重写其drawRect:方法进行绘制。当view变的可见的时候或者其内容需要更新的时候,view的drawRect:方法会被调用。在调用自定义的drawRect:方法之前,view对象会自动的配置其绘制环境,然后代码可以立即的绘制。作为配置的一部分,UIView对象先为当前的绘制环境创建一个Graphics Context。我们可以在drawRect:方法中通过调用UIKit的UIGraphicsGetCurrentContext
函数去得到此Graphics Context。
UIKit使用的缺省坐标系统与Quartz的坐标系统不相同。在UIKit中,原点在左上角。UIView对象通过translating 原点并且通过在y轴乘以-1来改变Quartz Graphics Context使其与UIKit相匹配。
下面是摘自iphone调参的DDProgressView类中的实现,该类是动画的进度条的实现。
- (void)drawBackgroundWithRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); { // Draw the white shadow [[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:0.2] set]; UIBezierPath* shadow = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0.5, 0, rect.size.width - 1, rect.size.height - 1) cornerRadius:_cornerRadius]; [shadow stroke]; // Draw the track [ProgressBarColorBackground set]; UIBezierPath* roundedRect = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, rect.size.width, rect.size.height-1) cornerRadius:_cornerRadius]; [roundedRect fill]; // Draw the inner glow,背景条目的底部效果,一根白色的线条,可以显示出凹凸的质感 [ProgressBarColorBackgroundGlow set]; CGMutablePathRef glow = CGPathCreateMutable(); CGPathMoveToPoint(glow, NULL, _cornerRadius, 0); CGPathAddLineToPoint(glow, NULL, rect.size.width - _cornerRadius, 0); CGContextAddPath(context, glow); CGContextDrawPath(context, kCGPathStroke); CGPathRelease(glow); } CGContextRestoreGState(context); } - (void)drawRect:(CGRect)rect { //... // Draw the background track [self drawBackgroundWithRect:rect]; //... }
iOS--Run Loop
NSRunLoop 允许在您等待时响应事件runloop。如果你只是睡了(调用sleep函数),您的线程即使事件到达 (比如你在等待的网络响应)也无法响应。
在连续循环中,有可能会引起界面的停顿,可以考虑加入[[NSRunLoop currentRunLoop] runUntilDate: [NSDate distantPast]]
,其实就是本身的loop暂停一下,让主线程分点时间。
首先是Run Loop的部分概念,它的作用就是循环、处理事件。具体来说有两个方面:
- 定时启动任务(一般用和Timer协作);
- 处理事件。
在单线程的app中,不需要注意Run Loop,但不代表没有。程序启动时,系统已经在主线程中加入了Run Loop。它保证了我们的主线程在运行起来后,就处于一种“等待”的状态(而不像一些命令行程序一样运行一次就结束了),这个时候如果有接收到的事件(Timer的定时到了或是其他线程的消息),就会执行任务,否则就处于休眠状态。
如果我们要写多线程的程序,可能就需要自己来管理Run Loop。
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]
RunMode: NSDefaultRunLoopMode,默认的run loop mode,可以把这个理解为一个”过滤器“,我们可以只对自己关心的事件进行监视。一般NSDefaultRunLoopMode是最常用的。
启动run loop的方法就是runMode:,它的说明是:Runs the loop once, blocking for input in the specified mode until a given date。启动run loop一次,在特定的run loop mode阻塞程序,直到有事件发生,或者设置的时间已经到期。blocking for input中input指的是需要响应的事件发生。
如果没有附加input source或是timer,或是时间过了limitDate,run loop就会退出阻塞状态,并且方法返回NO。
下来是Run Loop的使用场合:
- 使用port或是自定义的input source来和其他线程进行通信
- 在线程(非主线程)中使用timer
- 使用 performSelector...系列(如performSelectorOnThread, ...)
- 使用线程执行周期性工作
run loop不需要创建,在线程中只需要调用[NSRunLoop currentRunLoop]就可以得到。
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy) self.HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view]; [self.navigationController.view addSubview:self.HUD]; [self.HUD show:YES]; [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantPast]]; //登陆 NSNumber* loginResult = [[LoginRegist sharedInstance] Login:userName password:password]; [self.HUD hide:YES];
假设我们想要等待某个异步方法的回调。比如connection。如果我们的线程中没有启动run loop,是不会有效果的(因为线程已经运行完毕,正常退出了)。我们可以用一个条件来运行run loop。
这样就可以一直进行等待,直到在别的位置将done置为YES,表示任务完成。
-(void)start { isFinished = NO; ... while(isFinished != YES) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } }
while(done) { [ NSRunLoop currentRunLoop] runMode:currentMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; }
上面这段话看似程序进入了死循环,其实并不是这样。这段程序的意思是:
如果当前线程有当前设置的runMode下的事件发生,runloop就会启动,处理对应的事件。如果没有事件发生,runloop就会每过10秒钟启动一次当前线程的runloop.
如果runloop每次启动成功 [ NSRunLoop currentRunLoop] runMode:currentMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; 返回值为YES,这个启动成功包括了时间触发和10秒钟到了之后触发两种情况。如果启动失败返回false.
说到这个地方可能还不明白,为什么要搞个循环,为什么要用runloop,我刚开始的时候也是搞得不太明白。
这个地方解释一下:
当我们在ios设备上面触摸屏幕之后,对应的tounch事件就会调用,这是为什么呢,其实这个地方就有runloop的功劳。
其实runloop做为一种时间处理机制,类似一个车间的主任(不知道这种比喻是否恰当),这个主任他负责处理这个车间流水线上面发生特定类型事件的处理(这里的特定事件就是runMode)。这个事件可以包括安全事件,机械事件等等。该主任处理事件的传统方式可以是每隔一分钟巡逻生产线一次(对应的是cpu空转轮询消息队列的方式),这种方式比较耗费工人体力(cpu资源,电量),当发现有问题发生,他就找对应的工人去处理,这里的工人对应于时间的处理函数;还有一种方式就是主任平时都在睡觉打麻将,当生产线发生问题的时候,如果是属于他的职责,系统就直接给他发送一条短信通知他,他收到之后再通知对应的工人去处理,上面那个十秒钟(这个是可以更改的)就是如果十秒内没有消息通知过来,主任才会去车间巡逻一次,但是这十秒由于主任是没有收到事件处理消息的,所以他通常是到了车间就走了(对应runLoop启动就结束,没有事件处理)。
因此采用runloop的好处就显而易见了。
runloop处理的事件包括:
- 使用port或是自定义的input source来和其他线程进行通信
- 在线程(非主线程)中使用timer
- 使用 performSelector...系列(如performSelectorOnThread, ...)
- 使用线程执行周期性工作
如果在执行周期性工作的时候就可以采用上面那种,用一个循环,当时间回调的时候(这个地方的一个典型应用场景就是处理网络数据,网络有数据返回就启动一次runloop,直到所有数据处理完成之后将done设置为YES。结束);
iOS--其他
NSBundle与文件资源
获取app下的Error.html文件路径。
path = [[NSBundle mainBundle] pathForResource:@"Error" ofType:@"html"];
NSLocale language
判断当前的系统语言设置是否为中文简体。
if ([[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString:@"zh-Hans"]) { //中文用户 path = [[NSBundle mainBundle] pathForResource:@"Error" ofType:@"html"]; } else { //其他语言用户,都配置为英文 path = [[NSBundle mainBundle] pathForResource:@"Error_en" ofType:@"html"]; }
amazon库中try catch的使用
+ (NSMutableArray *)getFacets:(NSString *)withName { @try { AmazonS3Client * s3 = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY]; S3GetObjectRequest * request = [[S3GetObjectRequest alloc] initWithKey:withName withBucket:MODEL_BUCKET]; S3GetObjectResponse * response = [s3 getObject:request]; NSData * data = [response body]; // Convert it to list of points return [self getFacetsFromData:data]; } @catch (AmazonClientException * exception) { [self showAlert:exception.message withTitle:@"Download Error"]; } return [[NSMutableArray alloc] init]; }
定时器循环
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:@selector(scanMainControllerAssistantCmd) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode]; [timer fire]; [timer performSelector:@selector(invalidate) withObject:nil afterDelay:5.0f];
performSelector和respondsToSelector
performSelector函数用于对象调用它自己的方法。
//self这个对象调用它的方法_onScanMainCtrlTimer。如果改方法不存在,则会报错 [self performSelector:@selector(_onScanMainCtrlTimer:)];
对于delegate的实现时,也可以不使用performSelector函数。
[self.delegate ReconnectFinished:YES];
如果delegate是optional,需要respondsToSelector函数先判断其是否存在该这样的方法。
if ([self.delegate respondsToSelector:@selector(didScanMainControllerPeripheral:)]) { [self.delegate performSelector:@selector(didScanMainControllerPeripheral:) withObject:mainControllerPeripheral]; }
no appropriate for no-gc object
警告信息:“No 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed”和“Default property attribute 'assign' not appropriate for non-gc object”。警告信息的意思是:“没有明确指出应该是assign还是retain或者是copy,却省的是assign”和“缺省得属性设置assign不适合非gc对象 ”
ios程序基本的起始代码
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; // Override point for customization after application launch. self.listViewController = [[BLEListViewController alloc] initWithStyle:UITableViewStyleGrouped]; self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.listViewController]; self.window.rootViewController = self.navigationController; //[self.window addSubview:[self.navigationController view]]; [self.window makeKeyAndVisible];
nil指针被调用不会报错,区别于野指针
//如果不存在该成员,则返回的值为nil,后面的调用也不会报错 NSMutableArray * activeMainCtrl = [[NSUserDefaults standardUserDefaults] objectForKey:@"activeMainCtrl"]; [activeMainCtrl addObject:infoItem]; NSLog(@"[001] saved mc : %@",activeMainCtrl);
阻塞线程,sleep
[NSThread sleepForTimeInterval:30];
http get请求
//登陆 NSError *error; NSString *baseurl = [NSString stringWithFormat:@"http://test.skypedia.net/app/signin?user=%@&password=%@",yourEmail.inputField.text,password.inputField.text]; NSLog(@"base url: %@",baseurl); NSURL *url = [NSURL URLWithString:baseurl]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; [request setHTTPMethod:@"GET"]; [request setTimeoutInterval:8]; NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error]; if (!returnData) { NSLog(@"login failed: %@",[error localizedDescription]); UIAlertView* alter = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"login failed" ,@"") message:[error localizedDescription] delegate:self cancelButtonTitle:NSLocalizedString(@"OK" ,@"") otherButtonTitles:nil]; [alter show]; [alter release]; return; } else{ NSString *returnMsg = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; NSLog(@"return msg %@",returnMsg); //解析返回信息 if ([returnMsg hasPrefix:@"0 "]) { //登陆成功,修改默认登陆名和密码 [[NSUserDefaults standardUserDefaults] setObject:yourEmail.inputField.text forKey:@"UserName"]; [[NSUserDefaults standardUserDefaults] setObject:password.inputField.text forKey:@"password"]; [[NSUserDefaults standardUserDefaults] synchronize]; NSLog(@"Login action finish"); } else{ UIAlertView* alter = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"login failed" ,@"") message:returnMsg delegate:self cancelButtonTitle:NSLocalizedString(@"OK" ,@"") otherButtonTitles:nil]; [alter show]; [alter release]; } }
列举目录下的文件
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSLog(@"paths: %@",paths); NSString *documentsDirectory = [paths objectAtIndex:0]; NSLog(@"documentsDirectory: %@",documentsDirectory); NSFileManager *fileManage = [NSFileManager defaultManager]; NSArray *file = [fileManage subpathsOfDirectoryAtPath: documentsDirectory error:nil]; NSLog(@"%@",file); NSArray *files = [fileManage subpathsAtPath: documentsDirectory ]; NSLog(@"%@",files);
document目录
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSLog(@"rootPath %@",rootPath); NSString *path = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"]; NSLog(@"path: %@",path);
结果:rootPath /var/mobile/Applications/D14CF626-40EF-484D-A94D-72C649A483FD/Documents
结果:2012-12-15 14:03:50.236 AssistantForIphone[15065:907] path: /var/mobile/Applications/D14CF626-40EF-484D-A94D-72C649A483FD/AssistantForIphone.app/Config.plist
app跳转到系统程序
app跳转到浏览器,并且打开链接
#define FORGET_PASSWORD_URL @"http://login.dji-innovations.com/member/forget/en_US" [[UIApplication sharedApplication] openURL:[NSURL URLWithString:FORGET_PASSWORD_URL]];
app跳转到email,并且设置收件人
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://app@dji-innovations.com"]];