iOS多线程---GCD

22 篇文章 0 订阅
12 篇文章 0 订阅

转自:http://blog.csdn.net/shubinniu/article/details/53004672


概念


队列 (dispatch_queue_t)

队列名称在调试时辅助,无论什么队列和任务,线程的创建和回收不需要程序员操作,有队列负责。


串行队列:


队列中的任务只会顺序执行


dispatch_queue_t q = dispatch_queue_create(“....”,DISPATCH_QUEUE_SERIAL);


并行队列:


队列中的任务通常会并发执行


dispatch_queue_t q =dispatch_queue_create("......",DISPATCH_QUEUE_CONCURRENT);


全局队列:


是系统的,直接拿过来(GET)用就可以;与并行队列类似,但调试时,无法确认操作所在队列


dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);


主队 列:


每一个应用程序对应唯一一个主队列,直接GET即可;在多线程开发中,使用主队列更新UI


dispatch_queue_t q = dispatch_get_main_queue();


  :


dispatch_async异步操作,会并发执行,无法确定任务的执行顺序;


dispatch_sync同步操作,会依次顺序执行,能够决定任务的执行顺序;


  注:


全局队列可认为是并行队列的一个特例,这里不再列举。

线程、任务和队列对比

异步、同步 & 并行、串行的特点


一条重要的准则

一般来说,我们使用GCD的最大目的是在新的线程同时执行多个任务,这意味着我们需要两项条件:

  • 能开启新的线程
  • 任务可以同时执行
  • 结合以上两个条件,也就等价“开启新线程的能力 + 任务同步执行的权利”,只有在满足能力与权利这两个条件的前提下,我们才可以在同时执行多个任务。

所有组合的特点



(一)异步执行 + 并行队列
实现代码:

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //异步执行 + 并行队列  
  2. - (void)asyncConcurrent{  
  3.     //创建一个并行队列  
  4.     dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT);  
  5.   
  6.     NSLog(@"---start---");  
  7.   
  8.     //使用异步函数封装三个任务  
  9.     dispatch_async(queue, ^{  
  10.         NSLog(@"任务1---%@", [NSThread currentThread]);  
  11.     });  
  12.     dispatch_async(queue, ^{  
  13.         NSLog(@"任务2---%@", [NSThread currentThread]);  
  14.     });  
  15.     dispatch_async(queue, ^{  
  16.         NSLog(@"任务3---%@", [NSThread currentThread]);  
  17.     });  
  18.   
  19.     NSLog(@"---end---");  
  20. }  
打印结果:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ---start---  
  2.   ---end---  
  3.   任务3---<NSThread: 0x600000070f00>{number = 5, name = (null)}  
  4.   任务2---<NSThread: 0x600000070d80>{number = 4, name = (null)}  
  5.   任务1---<NSThread: 0x608000074100>{number = 3, name = (null)}  
解释
  • 异步执行意味着
    • 可以开启新的线程
    • 任务可以先绕过不执行,回头再来执行
  • 并行队列意味着
    • 任务之间不需要排队,且具有同时被执行的“权利”
  • 两者组合后的结果
    • 开了三个新线程
    • 函数在执行时,先打印了start和end,再回头执行这三个任务
    • 这三个任务是同时执行的,没有先后,所以打印结果是“任务3-->任务2-->任务1”
步骤图


(二)异步执行 + 串行队列
实现代码:

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //异步执行 + 串行队列  
  2. - (void)asyncSerial{  
  3.     //创建一个串行队列  
  4.     dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);  
  5.   
  6.     NSLog(@"---start---");  
  7.     //使用异步函数封装三个任务  
  8.     dispatch_async(queue, ^{  
  9.         NSLog(@"任务1---%@", [NSThread currentThread]);  
  10.     });  
  11.     dispatch_async(queue, ^{  
  12.         NSLog(@"任务2---%@", [NSThread currentThread]);  
  13.     });  
  14.     dispatch_async(queue, ^{  
  15.         NSLog(@"任务3---%@", [NSThread currentThread]);  
  16.     });  
  17.     NSLog(@"---end---");  
  18. }  

打印结果:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ---start---  
  2.  ---end---  
  3. 任务1---<NSThread: 0x608000078480>{number = 3, name = (null)}  
  4. 任务2---<NSThread: 0x608000078480>{number = 3, name = (null)}  
  5. 任务3---<NSThread: 0x608000078480>{number = 3, name = (null)}  
解释
  • 异步执行意味着
    • 可以开启新的线程
    • 任务可以先绕过不执行,回头再来执行
  • 串行队列意味着
    • 任务必须按添加进队列的顺序挨个执行
  • 两者组合后的结果
    • 开了一个新的子线程
    • 函数在执行时,先打印了start和end,再回头执行这三个任务
    • 这三个任务是按顺序执行的,所以打印结果是“任务1-->任务2-->任务3”
步骤图


(三)同步执行 + 并行队列
实现代码:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //同步执行 + 并行队列  
  2. - (void)syncConcurrent{  
  3.     //创建一个并行队列  
  4.     dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT);  
  5.   
  6.     NSLog(@"---start---");  
  7.     //使用同步函数封装三个任务  
  8.     dispatch_sync(queue, ^{  
  9.         NSLog(@"任务1---%@", [NSThread currentThread]);  
  10.     });  
  11.     dispatch_sync(queue, ^{  
  12.         NSLog(@"任务2---%@", [NSThread currentThread]);  
  13.     });  
  14.     dispatch_sync(queue, ^{  
  15.         NSLog(@"任务3---%@", [NSThread currentThread]);  
  16.     });  
  17.     NSLog(@"---end---");  
  18. }  

打印结果:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ---start---  
  2.   任务1---<NSThread: 0x608000065400>{number = 1, name = main}  
  3.   任务2---<NSThread: 0x608000065400>{number = 1, name = main}  
  4.   任务3---<NSThread: 0x608000065400>{number = 1, name = main}  
  5.   ---end---  

解释
  • 同步执行执行意味着
    • 不能开启新的线程
    • 任务创建后必须执行完才能往下走
  • 并行队列意味着
    • 任务必须按添加进队列的顺序挨个执行
  • 两者组合后的结果
    • 所有任务都只能在主线程中执行
    • 函数在执行时,必须按照代码的书写顺序一行一行地执行完才能继续
  • 注意事项
    • 在这里即便是并行队列,任务可以同时执行,但是由于只存在一个主线程,所以没法把任务分发到不同的线程去同步处理,其结果就是只能在主线程里按顺序挨个挨个执行了
步骤图


(四)同步执行+ 串行队列
实现代码:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. - (void)syncSerial{  
  2.     //创建一个串行队列  
  3.     dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL);  
  4.   
  5.     NSLog(@"---start---");  
  6.     //使用异步函数封装三个任务  
  7.     dispatch_sync(queue, ^{  
  8.         NSLog(@"任务1---%@", [NSThread currentThread]);  
  9.     });  
  10.     dispatch_sync(queue, ^{  
  11.         NSLog(@"任务2---%@", [NSThread currentThread]);  
  12.     });  
  13.     dispatch_sync(queue, ^{  
  14.         NSLog(@"任务3---%@", [NSThread currentThread]);  
  15.     });  
  16.     NSLog(@"---end---");  
  17. }  

打印结果:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ---start---  
  2. 任务1---<NSThread: 0x608000065400>{number = 1, name = main}  
  3. 任务2---<NSThread: 0x608000065400>{number = 1, name = main}  
  4. 任务3---<NSThread: 0x608000065400>{number = 1, name = main}  
  5. ---end---  

解释
这里的执行原理和步骤图跟“同步执行+并发队列”是一样的,只要是同步执行就没法开启新的线程,所以多个任务之间也一样只能按顺序来执行

(五)异步执行+主队列
实现代码:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. - (void)asyncMain{  
  2.     //获取主队列  
  3.     dispatch_queue_t queue = dispatch_get_main_queue();  
  4.   
  5.     NSLog(@"---start---");  
  6.     //使用异步函数封装三个任务  
  7.     dispatch_async(queue, ^{  
  8.         NSLog(@"任务1---%@", [NSThread currentThread]);  
  9.     });  
  10.     dispatch_async(queue, ^{  
  11.         NSLog(@"任务2---%@", [NSThread currentThread]);  
  12.     });  
  13.     dispatch_async(queue, ^{  
  14.         NSLog(@"任务3---%@", [NSThread currentThread]);  
  15.     });  
  16.     NSLog(@"---end---");  
  17. }  

打印结果:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ---start---  
  2. ---end---  
  3. 任务1---<NSThread: 0x60800006ff40>{number = 1, name = main}  
  4. 任务2---<NSThread: 0x60800006ff40>{number = 1, name = main}  
  5. 任务3---<NSThread: 0x60800006ff40>{number = 1, name = main}  

解释
  • 异步执行意味着
    • 可以开启新的线程
    • 任务可以先绕过不执行,回头再来执行
  • 主队列跟串行队列的区别
    • 队列中的任务一样要按顺序执行
    • 主队列中的任务必须在主线程中执行,不允许在子线程中执行
  • 以上条件组合后得出结果:
    • 所有任务都可以先跳过,之后再来“按顺序”执行
步骤图

(六)同步执行+主队列(死锁)
实现代码:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. - (void)syncMain{  
  2.     //获取主队列  
  3.     dispatch_queue_t queue = dispatch_get_main_queue();  
  4.   
  5.     NSLog(@"---start---");  
  6.     //使用同步函数封装三个任务  
  7.     dispatch_sync(queue, ^{  
  8.         NSLog(@"任务1---%@", [NSThread currentThread]);  
  9.     });  
  10.     dispatch_sync(queue, ^{  
  11.         NSLog(@"任务2---%@", [NSThread currentThread]);  
  12.     });  
  13.     dispatch_sync(queue, ^{  
  14.         NSLog(@"任务3---%@", [NSThread currentThread]);  
  15.     });  
  16.     NSLog(@"---end---");  
  17. }  

打印结果:
[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ---start---  

解释
  • 主队列中的任务必须按顺序挨个执行
  • 任务1要等主线程有空的时候(即主队列中的所有任务执行完)才能执行
  • 主线程要执行完“打印end”的任务后才有空
  • “任务1”和“打印end”两个任务互相等待,造成死锁
步骤图


(七)知识拓展
1.  dispatch_sync 同步应用场景

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. -(void)loginAction  
  2. {  
  3.     //阻塞并行队列的执行,要求某一操作执行后再进行后续操作,如用户登录  
  4.     //确保块代码之外的局部变量确实被修改  
  5.     dispatch_queue_t q = dispatch_queue_create("cn.login", DISPATCH_QUEUE_CONCURRENT);  
  6.     __block BOOL logon = NO;  
  7.     dispatch_sync(q, ^{  
  8.         NSLog(@"模拟耗时操作 %@", [NSThread currentThread]);  
  9.         [NSThread sleepForTimeInterval:2.0f];  
  10.         NSLog(@"模拟耗时完成 %@", [NSThread currentThread]);  
  11.         logon = YES;  
  12.     });  
  13.       
  14.     dispatch_async(q, ^{  
  15.           
  16.         NSLog(@"登录完成的处理 %@", [NSThread currentThread]);  
  17.     });  
  18. }  

2.  iOS三种多线程技术:

   1.NSThread

     (1)使用NSThread对象建立一个线程非常方便

     (2)但是!要使用NSThread管理多个线程非常困难,不推荐使用

     (3)技巧!使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术

   2.NSOperation/NSOperationQueue

     (1)是使用GCD实现的一套Objective-CAPI

     (2)是面向对象的线程技术

     (3)提供了一些在GCD中不容易实现的特性,如:限制最大并发数量、操作之间的依赖关系

   3.GCD —— Grand Central Dispatch

     (1)是基于C语言的底层API

     (2)Block定义任务,使用起来非常灵活便捷

     (3)提供了更多的控制能力以及操作队列中所不能使用的底层函数


3.  队列和线程的区别:

 队列:是管理线程的,相当于线程池,能管理线程什么时候执行。

  串行队列:队列中的线程按顺序执行(不会同时执行)

  并行队列:队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗,如果后面的任务执行完了,怎么出去的了。这里需要强调下,任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列。

4.   主线程队列和GCD创建的队列也是有区别的。

  主线程队列和GCD创建的队列是不同的。在GCD中创建的队列优先级没有主队列高,所以在GCD中的串行队列开启同步任务里面没有嵌套任务是不会阻塞主线程,只有一种可能导致死锁,就是串行队列里,嵌套开启任务,有可能会导致死锁。

  主线程队列中不能开启同步,会阻塞主线程。只能开启异步任务,开启异步任务也不会开启新的线程,只是降低异步任务的优先级,让cpu空闲的时候才去调用。而同步任务,会抢占主线程的资源,会造成死锁。

5. 线程:里面有非常多的任务(同步,异步)

  同步与异步的区别:

  同步任务优先级高,在线程中有执行顺序,不会开启新的线程。

 异步任务优先级低,在线程中执行没有顺序,看cpu闲不闲。在主队列中不会开启新的线程,其他队列会开启新的线程。

6.  主线程队列注意:

  在主队列开启异步任务,不会开启新的线程而是依然在主线程中执行代码块中的代码。为什么不会阻塞线程?

   主队列开启异步任务,虽然不会开启新的线程,但是他会把异步任务降低优先级,等闲着的时候,就会在主线程上执行异步任务。 

 7. 在主队列开启同步任务,为什么会阻塞线程?

  在主队列开启同步任务,因为主队列是串行队列,里面的线程是有顺序的,先执行完一个线程才执行下一个线程,而主队列始终就只有一个主线程,主线程是不会执行完毕的,因为他是无限循环的,除非关闭应用程序。因此在主线程开启一个同步任务,同步任务会想抢占执行的资源,而主线程任务一直在执行某些操作,不肯放手。两个的优先级都很高,最终导致死锁,阻塞线程了。 

8.  串行队列开启异步任务后嵌套同步任务造成死锁

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. - (void)serial_queue_deadlock  
  2.   
  3. {  
  4.     dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);  
  5.   
  6.     dispatch_async(q, ^{  
  7.    
  8.         NSLog(@"异步任务 %@", [NSThread currentThread]);  
  9.   
  10.         // 下面开启同步造成死锁:因为串行队列中线程是有执行顺序的,需要等上面开启的异步任务执行完毕,才会执行下面开启的同步任务。而上面的异步任务还没执行完,要到下面的大括号才算执行完毕,而下面的同步任务已经在抢占资源了,就会发生死锁。  
  11.   
  12.         dispatch_sync(q, ^{  
  13.             NSLog(@"同步任务 %@", [NSThread currentThread]);  
  14.         });  
  15.     });  
  16.   
  17. }  

  9. 串行队列开启同步任务后嵌套同步任务造成死锁

[objc]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. - (void)serial_queue_deadlock  
  2. {  
  3.     dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);  
  4.     dispatch_sync(q, ^{  
  5.         NSLog(@"同步任务 %@", [NSThread currentThread]);  
  6.         // 下面开启同步造成死锁:因为串行队列中线程是有执行顺序的,需要等上面开启的同步任务执行完毕,才会执行下面开启的同步任务。而上面的同步任务还没执行完,要到下面的大括号才算执行完毕,而下面的同步任务已经在抢占资源了,就会发生死锁。  
  7.         dispatch_sync(q, ^{  
  8.             NSLog(@"同步任务 %@", [NSThread currentThread]);  
  9.         });  
  10.    
  11.     });  
  12.   
  13.     NSLog(@"同步任务 %@", [NSThread currentThread]);  
  14. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
状态栏20键盘高度216导航44 最少2位 补0 // UIColor *color2 = [[UIColor alloc] initWithRed:0 green:1 blue:0 alpha:1]; // button setTitle:@"点我吧" forState:UIControlStateNormal]; // [button addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; Target目标 action行动 [button setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; //字体在点击时候的颜色 button.selected=YES;//激活forState:UIControlStateSelected状态 [UIButton buttonWithType:UIButtonTypeRoundedRect];按钮样式 button1.tag = [str intValue]; 标记 //initWithNibName将控制器绑定xib的方法,如果xib的名称和控制器的类名称相同的时候,直接写init(会自动绑定同名的xib)就可以,如果xib的名称和类名称不同的话,必须手动调用此方法来进行绑定 ZYTwoViewController *two=[[ZYTwoViewController alloc]initWithNibName:@"Empty" bundle:nil]; //因为UIImageView的用户可交互性默认是关闭的,所以把按钮放在他身上时,按钮是不能点击的,把可交互性打开以后,按钮就能够被点击 imgView.userInteractionEnabled=YES; enabled授权给 Interaction交互 //将序列帧数组赋给UIImageView的animationImages属性 imageview.animationImages = imageArray; //设置动画时间 imageview.animationDuration = 2; Duration持续时间 //设置动画次数 0 表示无限 imageview.animationRepeatCount = 0; Repeat重复次数 //开始播放动画 [imageview startAnimating]; / //要动画的对象和他的状态 // imageView.frame = CGRectMake(200, 200, 50, 50); // //设置透明度 // imageView.alpha = 0.2; //创建一个window对象,window的frame跟屏幕大小一致 self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; Screen 屏 //让window显示到屏幕上 [self.window makeKeyAndVisible]; Visible可见的 //得到全局的屏幕对象 UIScreen *screen = [UIScreen mainScreen]; //获得屏幕的大小 CGRect rect = screen.bounds; //判断btn这个指针指向的是UIButton的对象的时候才清空 if([btn isKindOfClass:[UIButton class]]){ [btn removeFromSuperview]; } //判断这个视图是否是他的父视图有 if([_imgView isDescendantOfView:cell]){ [_imgView removeFromSuperview]; } //让键盘放弃第一响应,也就是让textfield不再处于活动状态,键盘就会下去 //resignFirstResponder 这个方法的功能就是让属于textfield的键盘下去 [_textField resignFirstResponder]; resign失去 responder响应 //成为第一响应者 [_textField becomeFirstResponder]; become 变成 //enabled 可用的,textfield 不响应事件 //_salaryField.enabled = NO; // _textField.placeholder = @"请输入您的银行卡账号"; placeholder 占位符 // _textField.keyboardType = UIKeyboardTypeNumberPad; keyboard键盘 /secure 安全 text 文本 entry 输入 //textField.secureTextEntry = YES; //点击键盘的return键绑定当前类对象的down这个方法 //此方法可以有参数,也可以没有参数,如果没有参数系统不会给你穿参数,如果有参数,只能有一个参数,无论你所指定的参数类型是什么,系统只会把tf本身给传过去 [tf addTarget:self action:@selector(down:) forControlEvents:UIControlEventEditingDidEndOnExit]; //因为tag为999的本来就是UITextField类型所以可以强制转换成UITextField类型,如果他本来就不是UITextField,非要强转语法不会报错,但运行时就会出现问题(例如披着羊皮的郎) // UITextField *tf=(UITextField *)[self.window viewWithTag:999]; //让父视图取消编辑会让其身上的所有文本框都取消相应 [self.window endEditing:YES]; //将子视图在前面 [self.window bringSubviewToFront:_taiyang]; //超出这个view的边界的控件不再显示 [_infoView setClipsToBounds:YES]; //UIView 静态方法,开始一个动画 [UIView beginAnimations:nil context:nil]; begin 开始 //animation 动画 duration 间隔时间 [UIView setAnimationDuration:1]; //从当前状态设置动画开始 [UIView setAnimationBeginsFromCurrentState:YES]; //设置动画的重复次数,0表示1次 [UIView setAnimationRepeatCount:MAXFLOAT]; //设置动画的自动反转,出去以后原路返回 [UIView setAnimationRepeatAutoreverses:YES]; //设置动画的效果,慢入慢出 [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; //只有设置了context,并且设置代理和动画结束后调用的方法,系统会将context传过去 [UIView beginAnimations:nil context:imgView]; //设置代理(委托) [UIView setAnimationDelegate:self]; //设置动画结束以后调用的方法,我们只需要把context设置为imgView,系统就会调用此方法给传参数 [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; -(void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context{ NSLog(@"1111"); UIImageView *imgView=(UIImageView *)context; [imgView removeFromSuperview]; } //Transition 转换,变换 Curl 卷 //1.动画的样式 //2.要在哪个视图上做动画,一般是动画视图的父视图 [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:_window cache:YES]; //commit 提交 [UIView commitAnimations]; //索引为0表示先添加的子视图,跟子视图的tag没有关系 //交换两个子视图的先后位置 [self.window exchangeSubviewAtIndex:0 withSubviewAtIndex:1]; exchange交换 Subview 代替 //remove 移除 from 从 superview 父视图 //把自身从父视图中移除 //[_loginControl removeFromSuperview]; //设置数组容量为0,可变数组随便设置只是个初始化的值 _diJiArr=[[NSMutableArray alloc]initWithCapacity:0]; // CGAffineTransform a = {1,2,3,4,1,1}; //CGAffineTransformMakeRotation 方法的作用就是传进去一个角度(计量单位不是度,是弧度),方法内部帮你生成一个这个角度所对应的旋转矩阵 //rotate 旋转 CGAffineTransform a = CGAffineTransformMakeRotation(-3.1415926 / 2); //在原有imageView.transform的基础上再转多少度 CGAffineTransform c = CGAffineTransformRotate(imageView.transform, 3.1415926 / 2); //scale 缩放 // CGAffineTransform b = CGAffineTransformMakeScale(2, 2); //修改uiview 的矩阵,仿射变换 imageView.transform = a; //设置阴影偏移量(正值往右偏,正值往下偏移) label.shadowOffset=CGSizeMake(5, 10); //在oc中,空对象调用方法或属性不会引起程序报错或崩溃,但是也不会有任何事件发生 // NSString *str = nil; // [str length]; //判断两个字符串是否相等,不能使用==,使用等号是判断两个对象是否是一个对象,也就是是否是一个内存地址。 //判断字符串的内容是否相同应该使用nsstring的isEqualToString:方法 //在低版本的时候,如果直接点击注册按钮,没有点击具体的输入框,得到输入框中的内容为nil,如果点击输入框,但是没有输入任何内容,这个时候点击注册按钮获得的内容为@"".这是系统懒加载的结果。 // if ([registName isEqualToString:@""] || registName == nil) // { // NSLog(@"不能为空"); // return; // } //可以这样写,把上述两种情况都涵盖 //registName.length 获得字符串的长度 if (registName.length <= 0) //获取手指在屏幕上的坐标 UITouch * touch = [touches anyObject]; CGPoint point = [touch locationInView:self.view]; NSLog(@"ppp===%@",NSStringFromCGPoint(point)); CGPoint point=[[touches anyObject] locationInView:self.window]; //判断此时手指在屏幕上的坐标是否在飞机上,也就是说手指是否按在飞机上,如果是的话,改变飞机的中心点坐标到手指的位置上 if(CGRectContainsPoint(_planeView.frame, point)){ _planeView.center=point; } UIActionSheet *action=[[UIActionSheet alloc]initWithTitle:@"提示" delegate:self cancelButtonTitle:@"红" destructiveButtonTitle:@"绿" otherButtonTitles:@"蓝", nil]; [action showInView:self.view]; //弹出框 Alert 警告,alertView是局部变量,他的作用域只在if这个大括号内 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"警告" message:@"用户名不能为空" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil]; //show 展现 ,显示alertview [alertView show]; return; if (![_registPasswordField.text isEqualToString:_registConfirmPasswordField.text]) self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; //frame是相对于其父视图而言的 //bounds是相对于自身而言的,bounds的xy是设置自己坐标系的左上角坐标,会影响其子视图 //一般使用bounds不设置x和y只设置宽和高 //center是相对于其父视图而言的,是CGpoint类型 _vi.bounds=CGRectMake(0, 0, 200, 200); // vi.center=CGPointMake(160, 240); _vi.center=_window.center; //arc4random()%256取一个随机值,随机值的范围为0-255 _vi.backgroundColor=[UIColor colorWithRed:arc4random()%256/255.0 green:arc4random()%256/255.0 blue:arc4random()%256/255.0 alpha:1]; 屏幕触发事件 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event TestViewController *test=[[TestViewController alloc]init]; //实际作用就是将test的view放在window上 self.window.rootViewController=test; //initWithNibName将控制器绑定xib的方法,如果xib的名称和控制器的类名称相同的时候,直接写init(会自动绑定同名的xib)就可以,如果xib的名称和类名称不同的话,必须手动调用此方法来进行绑定 ZYTwoViewController *two=[[ZYTwoViewController alloc]initWithNibName:@"Empty" bundle:nil]; self.window.rootViewController=two; //每隔0.05秒调用当前类对象的boFang方法,不传参数,一直重复 _tim=[NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(boFang) userInfo:nil repeats:YES]; } scheduled 固定时间 Interval间隔时间 repeats重复 //bool orClose; -(void)btnPress{ // orClose=!orClose; //判断定时器的指针是否存在(定时器的对象是否存在) if(_tim){ //必须在定时器失效以后将定时器的指针至为空 [_tim invalidate]; invalidate使…无效 _tim=nil; }else{ _tim=[NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(boFang) userInfo:nil repeats:YES]; } /* int a=5,b=3; //三目运算符 int c=a>b?1:2; //不能深度赋值 //相当于 //imgView.frame.origin.y+=5; if(a>b){ c=1; }else{ c=2; } */ CGRectIntersectsRect(zidan.frame, diji.frame) //有交叉就怎么怎么样 //Activity 活动 Indicator指示器 // UIActivityIndicatorView *ai = [[UIActivityIndicatorView alloc] init]; // ai.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge; // ai.backgroundColor = [UIColor blackColor]; // ai.frame = CGRectMake(100, 200, 100, 100); // ai.hidesWhenStopped = NO; // [_loginControl addSubview:ai]; // [ai startAnimating]; //使用系统的协议方法:1、.h文件实现协议2、.m中设置委托3、.m实现协议方法 //点击alert身上的按钮的时候会调用此方法,并且会传参数 //switch创建对象的时候必须要加{},否则会编译不通过 //表示要实现协议,必须实现方法(什么也不写的情况下,默认是@required) @required -(void)doSomething:(NSString *)str; //表示要实现协议,可以实现也可以不实现方法 @optional -(void)doSomething2; 类相互交叉//告诉系统Man是一个类,此时用到Man不要再报错了,但是是不知道这个类有什么属性,和什么方法的 @class Man; //又因为.m中要用到属性和方法,所以仅仅用@class不行,再在.m中导入一下#import "Man.h" #import "Man.h" // MyView*vi=[[MyView alloc]initWithFrame:CGRectMake(<#CGFloat x#>, <#CGFloat y#>, <#CGFloat width#>, <#CGFloat height#>)] NSLog(@"111111"); //系统的init方法会去调用initwithFrame方法,此时的frame是0,0,0,0,所以无法确定按钮的位置 // MyView *vi=[[MyView alloc]init]; // MyView *vi=[[MyView alloc]initWithFrame:CGRectMake(0, 0, 0, 0)]; /* 1.找到应用程序的委托对象,这个对象的window就是手机屏幕上显示的window ZYAppDelegate *app=[UIApplication sharedApplication].delegate; app.window.rootViewController=reg; 2.因为委托对象的window是应用程序的主窗口,所以我们通过应用程序的对象调用keyWindow也可以找到手机屏幕上显示的widow [UIApplication sharedApplication].keyWindow.rootViewController=reg; */ 7T5A59~4UDE99@OU)WN0T`6.jpg ¬ //延时函数,调用refreash方法,传递参数,让这个方法在0.1秒以后调用 [self performSelector:@selector(refreash:) withObject:pickerView afterDelay:.1]; //只要控制器的视图将要显示都会执行此方法,所以这个方法不止执行一次 -(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:YES]; } -(void)viewDidDisappear:(BOOL)animated{ [super viewWillAppear:YES]; } //这2个方法都是不止执行一次 pickerView //设置pickerView分为几个区,此方法有一个参数,即设置的pickView - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{ NSLog(@"分区%d",pickerView.tag); //返回值是设置一共多少个区的 return 2; } //设置pickerView每个区分多少行,此方法有两个参数,分别为设置的哪个pickView和要设置的是哪个区 - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ NSLog(@"分行%d",pickerView.tag); if(component==0){ //返回值设置每个区的行数 return [_leftArr count]; } return [_rightArr count]; } //设置哪个pickView的哪个区的哪一行是什么标题, - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{ if(component==0){ //返回值设置每个行显示的内容 return [_leftArr objectAtIndex:row]; } return [_rightArr objectAtIndex:row]; } /当选中pickView某个区的某一行的时候会调用,第一个参数表示当前选择的是哪个pickView,第二个参数表示选择的是哪一行,第三个参数表示的是选择的哪一个区 - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ NSString *leftStr=nil; NSString *rightStr=nil; if(component==0){ leftStr=[_leftArr objectAtIndex:row]; int rightRow=[pickerView selectedRowInComponent:1]; rightStr=[_rightArr objectAtIndex:rightRow]; }else{ rightStr=[_rightArr objectAtIndex:row]; int leftRow=[pickerView selectedRowInComponent:0]; leftStr=[_leftArr objectAtIndex:leftRow]; } NSString *message=[NSString stringWithFormat:@"左边为:%@,右边为%@",leftStr,rightStr]; [[[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil] show];CocoaLigature1 - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ if(component==0){ //延时函数,调用refreash方法,传递参数,让这个方法在0.1秒以后调用 [self performSelector:@selector(refreash:) withObject:pickerView afterDelay:.1]; } } -(void)refreash:(UIPickerView *)pickerView{ [pickerView reloadComponent:1]; //加载每行相对应的行里的内容 [pickerView selectRow:0 inComponent:1 animated:YES]; }CocoaLigature1 UIDatePicker //UIDatePicker是处理时间的一个控件,继承于UIControl ,UIPickView继承于UIView,两者没有直接联系 UIDatePicker *pick=[[UIDatePicker alloc]initWithFrame:CGRectMake(0, 0, 320, 240)]; pick.tag=98; //控件的4种样式 pick.datePickerMode=UIDatePickerModeDateAndTime; //[NSDate date]获取当前日期 //pick.minimumDate=[NSDate date]; //显示多久以后的日期 pick.minimumDate=[NSDate dateWithTimeInterval:5*60*60 sinceDate:[NSDate date]]; [pick addTarget:self action:@selector(getTime:) forControlEvents:UIControlEventValueChanged]; [self.view addSubview:pick]; } -(void)getTime:(UIDatePicker *)pick{ NSDate *date=[pick date]; //格式化日期类,用这个类将nsdate转换成nsstring,也可以按反向转换 NSDateFormatter *formater=[[NSDateFormatter alloc]init]; //设置上午下午标示符,默认是上午和下午 [formater setAMSymbol:@"morning"]; [formater setPMSymbol:@"evening"]; //yyyy表示年 MM表示月 dd表示日 eeee表示星期几 HH表示24时制得小时,hh表示12时制得小时,mm表示分钟,ss表示秒 a表示上午下午 [formater setDateFormat:@"yyyy年MM月dd日 eeee hh:mm:ss a"]; NSString *str=[formater stringFromDate:date]; NSLog(@"%@",str); } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ NSString *str=@"2015年06月10日 08:53:52"; NSDateFormatter *formater=[[NSDateFormatter alloc]init]; [formater setDateFormat:@"yyyy年MM月dd日 hh:mm:ss"]; ((UIDatePicker *)[self.view viewWithTag:98]).date=[formater dateFromString:str]; ck];CocoaLigature1 UIScrollView //设置内容大小 sc.contentSize=CGSizeMake(200*8, 200); //设置成单页滑动 sc.pagingEnabled=YES; //设置内容偏移量 sc.contentOffset=CGPointMake(200, 0); //设置水平滚动条是否显示 sc.showsHorizontalScrollIndicator=NO; //设置垂直滚动条是否显示 sc.showsVerticalScrollIndicator=NO; //因为此时我们没有用手拨动,所以这个方法不会调用 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ NSLog(@"1111"); int num= scrollView.contentOffset.x/200; UIPageControl *page=(UIPageControl *)[self.view viewWithTag:2]; page.currentPage=num; } //只要scrollView发生偏移就会调用 - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ _pageControl.currentPage=_topView.contentOffset.x/320; } // self.automaticallyAdjustsScrollViewInsets=NO; //因为当前的控制器在导航器中,又在这个控制器的view身上先放的是UIScrollView,就会导致所有放在这个UIScrollView身上的空间向下偏移 //两种解决方法:1、不先放置这个UIScrollView //2、将控制器的automaticallyAdjustsScrollViewInsets这个属性设置成NO UIPageControl //设置page有多少页 page.numberOfPages=8; //设置page的当前页,索引从0开始 page.currentPage=1; //设置点的颜色 page.pageIndicatorTintColor=[UIColor redColor]; //设置当前页的点对应的颜色 -(void)change:(UIPageControl *)page{ int num=page.currentPage; UIScrollView *sc=(UIScrollView *)[self.view viewWithTag:1]; //sc.contentOffset=CGPointMake(200*num, 0); [sc setContentOffset:CGPointMake(200*num, 0) animated:YES]; } 导航栏 //压栈,出栈 ZYOneViewController *one=[[ZYOneViewController alloc]init]; //创建一个导航器,并且指定他的根控制器 //导航栏高度44 UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:one]; self.window.rootViewController=nav;CocoaLigature1 //这是控制器的属性,对这个属性赋值,并不会影响导航器的所有返回按钮,只是代表,当这个控制器在导航器中显示的时候,导航栏上的项目 self.navigationItem.leftBarButtonItem=[[UIBarButtonItem alloc]initWithTitle:@"回去" style:UIBarButtonItemStyleBordered target:self action:@selector(goBack)]; 模态跳转 -(void)gotoNext{ ZYThreeViewController *three=[[ZYThreeViewController alloc]init]; //设置翻转动画,是枚举类型 three.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal; //控制器与控制器之间跳转,模态跳转 [self presentViewController:three animated:YES completion:nil]; } - (IBAction)goBack:(UIButton *)sender { [self dismissViewControllerAnimated:YES completion:nil]; } //a模态b(a和b都不在导航其中)那么 //a的presentedViewController就是b //b的presentingViewController就是a UIWebView _web=[[UIWebView alloc]initWithFrame:CGRectMake(0, 74, 320, 430-44)]; //设置自适应大小 _web.scalesPageToFit=YES; [self.view addSubview:_web]; [_web loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:_urlArr[num-1]]]]; NSDictionary 字典 NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys:btn.titleLabel.font,NSFontAttributeName, nil]; float width= [_titleArr[num-1] sizeWithAttributes:dic].width; UITableView 用TableViewController创建 //注册单元格,表示此单元格可以被重复使用 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; tab=[[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain]; 用ViewController创建 _tab.delegate=self; _tab.dataSource=self; //设置单元格点击状态为无 cell.selectionStyle = UITableViewCellSelectionStyleNone; //设置单元格的样式为无 _tab.separatorStyle = UITableViewCellSeparatorStyleNone; //设置单元格的行高,在此设置会导致所有的行高都为80 _tab.rowHeight=80; [self.view addSubview:_tab]; //方法的返回值就是设置这个表有多少个区的,默认是1个区 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ return 2; } //设置特定的行高,当两者都设置时,以此为准 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 40; } //设置某个区的行数,方法有两个参数,第一个参数就是设置委托的表,第二个参数就是要设置的是哪个区,此方法的返回值表示要设置这个区的行数 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return 5*(section+1); } //设置区头标题 -(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{ return [NSString stringWithFormat:@"第%d区",section]; } //设置区头的高 -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ return 30; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //设置一个重用标示符 static NSString *cellIndentifier=@"cell"; //每次代码执行的时候先从tableView的重用队列里面去寻找有没有可以重复使用的单元格 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:cellIndentifier]; //如果没有找到可以重用的单元格,那么就去创建单元格 if(!cell){ cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIndentifier]autorelease]; //把每个单元格共有的东西放在此处 cell.detailTextLabel.text=@"你好"; cell.imageView.image=[UIImage imageNamed:@"c_item0.jpg"]; //按钮样式 cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator; //设置单元格选择样式 cell.selectionStyle=UITableViewCellSelectionStyleNone; } //把每个单元格不同的东西放在此处 cell.textLabel.text=[NSString stringWithFormat:@"第%d区,第%d行",indexPath.section,indexPath.row]; return cell; } xib //获取资源目录,加载xib文件,返回值类型为数组,数组中存放的是xib中除了fileOwner 和firstResponder以外的控件 cell= [[NSBundle mainBundle] loadNibNamed:@"ZYMyTwoTableViewCell" owner:nil options:nil][0]; MyTableViewCell *cell=(MyTableViewCell *)btn.superview.superview.superview; //通过单元格找到其对应的indexPath对象 NSIndexPath *indexPath=[_tab indexPathForCell:cell]; 分线程 //开启一个线程调用当前对象的update2方法,不传参数,当update2方法执行完成后分线程就结束了 [NSThread detachNewThreadSelector:@selector(update2) toTarget:self withObject:nil]; //因为分线程中不能直接改变UI,所以要从分线程中调到主线程去修改UI //回到主线程去执行其refreshUI这个方法,yes表示先阻碍当前的分线程,等到主线程的refreshUI这个方法执行完成后,回到分线程 //NO表示不等到主线程完成后才回来 [self performSelectorOnMainThread:@selector(refreshUI) withObject:nil waitUntilDone:YES]; 有时候配合延迟函数使用 [NSThread sleepForTimeInterval:.05];

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值