多线程之NSThread的使用-利弊用法

多线程使用情况:

1、耗时,而且很难知道什么时候会结束(如下载视频小说等)

2、游戏中播放声音 

每个进程启动之后,会有一个主线程

遇到耗时的操作时,新建线程去执行,可以保证主线程流畅

主线程是其他线程的最终父线程, 所有界面的显示操作必须在主线程进行

后台线程无法更新UI界面和响应用户点击事件
系统中每一个进程都有自己独立的虚拟内存空间,而同一个进程中多个线程公用进程的内存空间

每创建一个新的线程,都会消耗一定的内存和CPU时间,要控制线程执行顺序
当多个线程对同一个资源出现争夺时要注意线程安全问题

主线程堆栈大小是1M,第二个线程开始512kb

NSLog(@"大任务%@",[NSThread currentThread]);


<NSThread: 0x10950f2f0>{name = (null), num = 1}

num = 1说明是主线程


多线程是异步的,谁先谁后很难判断,不因代码书写先后改变


线程休眠,[NSThread sleepForTimeInterval:2];值适用于开发调试使用


下面上代码验证例子:

//
//  MainViewController.m
//  多线程-01.大任务
//
//  Created by admin on 14-10-9.
//  Copyright (c) 2014年 admin. All rights reserved.
//

#import "MainViewController.h"
/*
 1、[NSThread currentThread]可以返回当前的运行线程
    num = 1 说明是主线程
    在任何多线程技术中(NSThread,NSOperation,GCD)都可以调用此方法查看明细
 2、新建后台线程,[self performSelectorInBackground:@selector(bigTask) withObject:nil];
    一般不在主线程中是不可以修改UI内容的,但是performSelectorInBackground可以修改
    尽管如此,我们还是不应该在其他线程中修改UI内容
 3、更新界面
    使用performSelectorOnMainThread可以在主线程上执行任务。
    NSObject对象都可以调用此方法
 4、线程任务要含在自动释放池里面,否则容易引起内存泄露,而且很难发现
 */
@interface MainViewController ()
@property (weak, nonatomic) UIImageView *imageView;
@end

@implementation MainViewController
#pragma mark - 耗时操作
- (void)bigTask
{
  
    for (NSInteger i = 0; i < 500; i++) {
        NSString *str = [NSString stringWithFormat:@"字符串%zi",i];
 <span style="white-space:pre">	</span>NSLog(@"%@",str);
    }
    NSLog(@"大任务%@",[NSThread currentThread]);
}

#pragma mark - 不耗时操作
- (void)smallTask
{
    NSLog(@"小任务%@",[NSThread currentThread]);
    NSString *str = nil;
    for (NSInteger i = 0; i < 30000; i++) {
        str = [NSString stringWithFormat:@"****************%zi",i];
    }
    NSLog(@"%@",str);
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [btn1 setFrame:CGRectMake(110, 100, 100, 40)];
    [btn1 setTitle:@"大事件" forState:UIControlStateNormal];
    [btn1 addTarget:self action:@selector(button1) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn1];
    
    
    UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [btn2 setFrame:CGRectMake(110, 200, 100, 40)];
    [btn2 setTitle:@"小事件" forState:UIControlStateNormal];
    [btn2 addTarget:self action:@selector(button2) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn2];
    
    UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(110, 260, 100, 100)];
    UIImage *image = [UIImage imageNamed:@"头像1.png"];
    [imageView setImage:image];
    self.imageView = imageView;
    [self.view addSubview:imageView];
}

- (void)button1
{
    //在后台调用耗时操作
    //会新建一个后台线程,并且在该线程中执行调用方法
    [self performSelectorInBackground:@selector(bigTask) withObject:nil];
//    [self bigTask];
    //不等上句话执行完就开始执行,因为是一个执行流,上一句话重新开了一个进程
    NSLog(@"@@@@@@@@@@%@",[NSThread currentThread]);
    //可以改变UI,但是不建议这么使用,在主进程中改UI
    UIImage *image = [UIImage imageNamed:@"头像2.png"];
//    [self.imageView setImage:image];
    
    @autoreleasepool {//main.m里面的只能管理主线程的,如果涉及到其他线程的最后用自动释放池包含一下
        //在主线程中修改image
        //    [self performSelectorOnMainThread:@selector(changedImage:) withObject:image waitUntilDone:YES];
        [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
        
    }
}
- (void)button2
{
    [self smallTask];

}
- (void)changedImage:(UIImage *)image
{
    NSLog(@"修改图片%@",[NSThread currentThread]);
    [self.imageView setImage:image];
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

如果button1的操作不在后台中操作,大事件点击后要等所有的打印操作完成之后才能点击小事件

打印是非常耗时的操作,所以在程序正式运行时最好把nslog关掉


优点:

1、使用简单,轻量级;

缺点:

1、缺点是不能控制线程的执行顺序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值