• 在多线程中进行UI操作


    转载自   http://blog.csdn.net/developer_zhang/article/details/8910919

    iOS 上不建议在非主线程进行UI操作,在非主线程进行UI操作有很大几率会导致程序崩溃,或者出现预期之外的效果。

    我开始不知道这一点,在子线程中进行了弹窗操作,结果程序就出问题了!

    报的错误是(EXC_BAD_ACCESS(code=2,address=0xcc),0x1a0ad32: movl 204(%ecx), %edx ),我以为是空指针导致的内存泄露,用了很多方法,但这问题感觉很顽固,困扰了我很多天。

    后来有位大牛指点了我,问我是不是在子线程进行这个弹窗操作。。。直到此时我才明白问题出在哪里,问题顺利解决。有时候出现bug却不知道是哪引起的,这时是最纠结的,等明确了问题所在,问题就不是问题了。好了,言归正传。

    那么在子线程中的UI操作如何处理呢?有两种方法:

    一:在子线程,你需要进行的UI操作前添加dispatch_async函数,即可将代码块中的工作转回到主线程

     dispatch_async(dispatch_get_main_queue(), ^{  
                //更新UI操作  
                //.....  
            });

     dispatch_async函数是异步操作,对于比较耗时的操作也可以这样处理: 

    复制代码
    dispatch_async(dispatch_get_global_queue(0, 0), ^{  
        // 处理耗时操作的代码块...  
          
        //通知主线程刷新  
        dispatch_async(dispatch_get_main_queue(), ^{  
            //回调或者说是通知主线程刷新,  
        });  
          
    });
    复制代码

    dispatch_async开启一个异步操作,第一个参数是指定一个gcd队列,第二个参数是分配一个处理事物的程序块到该队列。

     dispatch_get_global_queue(0, 0),指用了全局队列。

    一般来说系统本身会有3个队列。

    global_queue,current_queue,以及main_queue.

    获取一个全局队列是接受两个参数,第一个是我分配的事物处理程序块队列优先级。分高低和默认,0为默认2为高,-2为低

     二:performSelectorOnMainThread

    performSelectorOnMainThread是指在主线程上执行某个方法,比如数据下载后,更新UI界面等操作

      例如:在子线程中使用[self performSelectorOnMainThread:@selector(endThread) withObject:nil waitUntilDone:NO];

    复制代码
    -(void)setupThread:(NSArray*)userInfor{  
      
       [NSThread detachNewThreadSelector:@selector(threadFunc:) toTarget:self withObject:(id)userInfor];  
      
    }  
      
    - (void)threadFunc:(id)userInfor{  
      
       NSAutoreleasePool*pool = [[NSAutoreleasePool alloc] init];  
      
       //。。。。需要做的处理。  
      
       //这里线程结束后立即返回  
      
      [self performSelectorOnMainThread:@selector(endThread) withObject:nil waitUntilDone:NO];  
      
      [pool release];  
      
    }  
    复制代码

    performSelectorOnMainThread通知主线程执行函数endThread。

    再次强调子线程内不要进行任何UI操作,不要刷新界面。如果需要进行这些操作,通过dispatch_async或performSelectorOnMainThread这两种方法,调出主线程中的方法去执行。

    --------------------------------------------

    IOS开发(62)之GCD上异步执行非UI任务

    分类: IOS开发

    1 前言

    如果想要在 GCD 的帮助下能够异步执行 Non-UI 相关任务。在主队列、串行队列和并发队列上异步执行代码块才能见识到 GCD 的真正实力。 

    要在分派队列上执行异步任务,你必须使用下面这些函数中的其中一个:

    dispatch_async

    为了异步执行向分派队列提交一个 Block Object(2 个都通过函数指定);

    eg:dispatch_sync(concurrentQueue, printFrom1To1000);

    dispatch_async_f

    为了异步执行向分派队列提交一个 C 函数和一个上下文引用(3 项通过函数指定) 。

    eg:dispatch_sync_f(concurrentQueue,NULL,printFrom1To1000); 

    2 代码实例

    这节代码有点多,所以分了两个工程

    First:ZYViewController.m

    1. - (void) viewDidAppear:(BOOL)paramAnimated{  
    2.     //新建一个队列  
    3.     dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
    4.     //执行concurrentQueue队列  
    5.     dispatch_async(concurrentQueue, ^{  
    6.         __block UIImage *image = nil;  
    7.         dispatch_sync(concurrentQueue, ^{  
    8.             /*下载图片*/  
    9.             /* 声明图片的路径*/  
    10.             NSString *urlAsString = @"http://images.apple.com/mobileme/features/images/ipad_findyouripad_20100518.jpg";  
    11.             //转换为NSURL对象  
    12.             NSURL *url = [NSURL URLWithString:urlAsString]; NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];  
    13.             //声明NSError对象:一个NSError对象封装错误信息更丰富、更具可扩展性可以只使用一个错误代码和错误字符串。  
    14.             NSError *downloadError = nil;  
    15.             //获得对应的Url返回的数据(这里是一个图片的数据)  
    16.             NSData *imageData = [NSURLConnection  
    17.                                  sendSynchronousRequest:urlRequest returningResponse:nil error:&downloadError];  
    18.             if (downloadError == nil &&imageData != nil){  
    19.                 //将NSData转换为图片  
    20.                 image = [UIImage imageWithData:imageData]; /* We have the image. We can use it now */  
    21.             }  
    22.             else if (downloadError != nil){  
    23.                 NSLog(@"Error happened = %@", downloadError);  
    24.             }else{  
    25.                 NSLog(@"No data could get downloaded from the URL.");  
    26.             }  
    27.         });  
    28.         dispatch_sync(dispatch_get_main_queue(), ^{  
    29.             /* 在主线程里面显示图片*/  
    30.             if (image != nil){  
    31.                 /* 穿件UIImageView视图 */  
    32.                 UIImageView *imageView = [[UIImageView alloc]  
    33.                                           initWithFrame:self.view.bounds];  
    34.                 /* 设置Image */  
    35.                 [imageView setImage:image];  
    36.                 /* 内容适应视图的大小通过保持长宽比*/  
    37.                 [imageView setContentMode:UIViewContentModeScaleAspectFit];  
    38.                 /* 想Controller View添加图像视图 */  
    39.                 [self.view addSubview:imageView];  
    40.             } else {  
    41.                 NSLog(@"Image isn't downloaded. Nothing to display.");  
    42.             } });  
    43.     });  
    44. }  

    运行结果


    Second:

    ZYViewController.h

    1. #import <UIKit/UIKit.h>  
    2.   
    3. @interface ZYViewController : UIViewController  
    4.   
    5. @property(nonatomic,strong) UILabel *myLabel;  
    6.   
    7. @end  

    ZYViewController.m

    1. @synthesize myLabel;  
    2.   
    3. - (void)viewDidLoad  
    4. {  
    5.     [super viewDidLoad];  
    6.     //声明一个队列  
    7.     dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  
    8.     /*  
    9.      如果我们还没有保存1000个随机数在磁盘上,下面的队列就用来生成这个文件并且用一个Array存放在磁盘上  
    10.      */  
    11.     dispatch_async(concurrentQueue, ^{  
    12.         NSUInteger numberOfValuesRequired = 10000;  
    13.         //判断文件是否存在  
    14.         if ([self hasFileAlreadyBeenCreated]== NO){  
    15.             dispatch_sync(concurrentQueue, ^{  
    16.                 //声明一个可变数组用来存放数值  
    17.                 NSMutableArray *arrayOfRandomNumbers =[[NSMutableArray alloc] initWithCapacity:numberOfValuesRequired];  
    18.                 NSUInteger counter = 0;  
    19.                 for (counter = 0;counter < numberOfValuesRequired;counter++){  
    20.                     //获得随机数  
    21.                     unsigned int randomNumber =arc4random() % ((unsigned int)RAND_MAX + 1);  
    22.                     [arrayOfRandomNumbers addObject:[NSNumber numberWithUnsignedInt:randomNumber]];  
    23.                 }  
    24.                 //将这个array写入到磁盘上  
    25.                 [arrayOfRandomNumbers writeToFile:[self fileLocation] atomically:YES];  
    26.                   
    27.             });  
    28.         }  
    29.     //存放读取文件内容的数组  
    30.     __block NSMutableArray *randomNumbers = nil;  
    31.     //从磁盘上读取文件并升序排列  
    32.     dispatch_sync(concurrentQueue, ^{  
    33.         //如果文件已经被创建,读取他  
    34.         if ([self hasFileAlreadyBeenCreated]){  
    35.             randomNumbers = [[NSMutableArray alloc] initWithContentsOfFile:[self fileLocation]];  
    36.             /* 排序 */  
    37.             [randomNumbers sortUsingComparator:^NSComparisonResult(id obj1, id obj2)  
    38.              {  
    39.                  NSNumber *number1 = (NSNumber *)obj1;  
    40.                  NSNumber *number2 = (NSNumber *)obj2;  
    41.                  return [number1 compare:number2];  
    42.              }];  
    43.         }  
    44.     });  
    45.     dispatch_async(dispatch_get_main_queue(), ^{  
    46.         if ([randomNumbers count] > 0){  
    47.         /* 刷新主线程 */  
    48.             CGRect labelFrame = CGRectMake(0.0f, 0.0f, 300.0f, 200.0f);  
    49.             self.myLabel = [[UILabel alloc] initWithFrame:labelFrame];  
    50.             self.myLabel.numberOfLines = 10;//分10行  
    51.             NSString *str = [[NSString alloc] initWithFormat:@"RandomNumbers is %@",randomNumbers];//方法一  
    52.             self.myLabel.text = str;//label的文字  
    53.             self.myLabel.font = [UIFont boldSystemFontOfSize:14.0f];//字体样式  
    54.             self.myLabel.center = self.view.center;//UILabel控件居中  
    55.             [self.view addSubview:self.myLabel];  
    56.         }  
    57.     });  
    58.     });  
    59. }  
    60.   
    61. //获得文件路径  
    62. -(NSString *)fileLocation{  
    63.     /*   
    64.      创建一个列表的目录搜索路径。  
    65.      NSDocumentDirectory:文档目录。  
    66.      NSUserDomainMask:用户的主目录的地方,存放用户的个人项目。   
    67.      */  
    68.     NSArray *folders = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);  
    69.     /* 如果没有找到返回空 */  
    70.     if ([folders count] == 0)  
    71.     {return nil; }  
    72.     /* 获得文件路径的字符串形式 */  
    73.     NSString *documentsFolder = [folders objectAtIndex:0];  
    74.     //将文件名追加到foldser后面  
    75.     return [documentsFolder stringByAppendingPathComponent:@"list.txt"];  
    76. }  
    77.   
    78. //判断文件是否被存在  
    79. - (BOOL) hasFileAlreadyBeenCreated{  
    80.     BOOL result = NO;  
    81.     //初始化NSFileManager文件管理对象  
    82.     NSFileManager *fileManager = [[NSFileManager alloc] init];  
    83.     //判断文件是否存在  
    84.     if ([fileManager fileExistsAtPath:[self fileLocation]])  
    85.     {  
    86.         result = YES;  
    87.     }  
    88.     return result;  
    89. }  

    运行结果


     

  • 相关阅读:
    Linux下svn服务器搭建
    mybatis-generator自动生成代码插件使用详解
    java中Class.forName("xxx")和ClassLoader().loadClass("xxx")的区别
    ExecutorService中submit()和execute()的区别
    Redis学习总结(1)——数据持久化
    Java内存模型及性能优化
    (转)Lock和synchronized比较详解
    SpringBoot中获取spring.profiles.active
    SpringBoot添加拦截器
    SpringBoot与Kafka集成
  • 原文地址:https://www.cnblogs.com/allanliu/p/4210303.html
Copyright © 2020-2023  润新知