iOSer 的自我修养ios 基础 面试

IOS多线程二 NSThread简约而不简单

2016-09-20  本文已影响292人  我妈说我是做工程师的料

IOS多线程二NSThread简约而不简单

今天就来着手教大家在IOS中简单的实现多线程。IOS实现多线程的方式有几种,但是要说最容易上手的还是NSThread,在IOS实现多线程的几种方法中,在我看来其实没有明显的好坏之分,只有适合之说,看何种场景下适合使用何种方式。

NSThread相对来说更加轻量级,并且更加具体,没有那么抽象,一个线程就是一个类的对象。你可以给这个对象附上需要执行的内容,其实也就是一个方法,可以通过调用该类的相关方法,控制其启动、关闭、暂停等。好吧,这里就不多说了,下面着重看下NSThread这个类。

直接在Xcode中就可以进入到NSThread类的.h文件中。可以看到NSThread是一个NSObject类的子类,是IOS开发的一个重要子框架Foundation框架中的一个类。进入NSThread类的.h文件可以看到一些NSThread比较常见的方法和属性。如下所述:

1.NSThread的init方法。

- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullableid)argumentNS_AVAILABLE(10_5,2_0);

该方法主要是用一个目标对象的方法来创建一个多线程NSThread类。其中target参数传递目标对象,selector参数传递目标对象的一个方法,其实就是多线程需要执行的内容。argument可以传递一个临时参数到多线程执行的方法中。

2.Start方法

该方法是控制线程启动执行的方法。init方法创建的NSThread对象,只有调用该方法才能启动执行。

3.detachNewThreadSelector方法

+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullableid)argument;

该方法与init方法类似,参数也是一样,区别就在于,init方法初始化好一个多线程对象之后,需要调用start方法启动执行,而该方法创建好后直接自己启动执行,不需要再调用start方法。并且也不会产生显示的对象,无法通过对象的方法来控制结束或者暂停执行线程。

4.类方法isMultiThreaded

+ (BOOL)isMultiThreaded;

判断当前代表执行是否在主线程中

5.类方法currentThread

+ (NSThread*)currentThread;

获取当前线程。

6.线程暂停方法

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

该方法可传递一个秒级别的参数ti,来暂停执行当前代码所在的线程ti秒。

7.退出线程方法

+ (void)exit;

该方法是真正可以让线程退出的方法,在某个线程中调用该方法,该线程就会直接退出,之后的代码就不会再执行,而且要特别指出,该方法如果直接在主线程中调用的话,连主线程都会被直接终止哦,主线程如果都被终止了,那等于整个程序就已经失去活力了,APP都会整个卡死。

8 cancle标志方法

- (void)cancelNS_AVAILABLE(10_5,2_0);

@property(readonly,getter=isCancelled)BOOLcancelledNS_AVAILABLE(10_5,2_0);

很多初学者以为cancel就是退出线程,其实不是,这里的cancel其实就是类中的一个BOOL型变量,用户调用了cancel方法,该BOOL型变量就变成了真,再调用isCancel就可以看到其值是YES还是NO,然后再根据该标志位做一些工作。所以对比一下退出线程还是要靠exit方法,或者直接在线程中判断调用return退出。

9 设置线程优先级

+ (BOOL)setThreadPriority:(double)p;

@propertydoublethreadPriorityNS_AVAILABLE(10_6,4_0);// To be deprecated; use qualityOfService below

通过以上方法可以查看和设置线程优先级,优先级高的线程会优先执行,这里不建议进行此类设置,会打乱系统之前的线程优先级安排。可能造成某些底等级的线程卡顿或者长时间得不到执行。

以上大致就是NSThread类已经类中相关的属性和方法的基本介绍。下面就讲3个具体使用NSThread实现多线程的例子。

1.启动一个线程

代码示例

- (void)viewDidLoad 

{

     [super viewDidLoad];//进入某个viewController时启动一个线程

     //使用已经写好的线程执行方法FunctionForNSThread初始化一个NSThread类对象

     NSThread* nowTestThread = [[NSThread alloc] initWithTarget:self selector:@selector(FunctionForNSThread) object:nil];

     //启动该线程类对象

     [nowTestThread start];

}

- (void)FunctionForNSThread

{

      if([NSThread isMainThread])//使用NSThread类方法isMainThread判断当前线程是否为主线程

      {//主线程输出信息

             NSLog(@"now is in MainThread");

      }

      else

      {//非主线程输出信息

             NSLog(@"now is not in MainThread");

      }

}

这里的输出结果为

2016-09-20 23:12:25.566 MultiThreadExample[622:15261] now is not in MainThread

说明我们已经启动了另外一个线程。

2.启动一个循环执行的线程。

- (void)viewDidLoad 

{

     [super viewDidLoad];//进入某个viewController时启动一个线程

     //使用已经写好的线程执行方法FunctionForNSThread初始化一个NSThread类对象

     NSThread* nowTestThread = [[NSThread alloc] initWithTarget:self selector:@selector(FunctionForNSThread) object:nil];

     //启动该线程类对象

     [nowTestThread start];

}

- (void)FunctionForNSThread

{

      intnowIndex =0;

      while(YES)//while循环执行

      {

           nowIndex++;

           [NSThread sleepForTimeInterval:1];//每次执行到这里让线程暂停1秒钟

           if([NSThread isMainThread])//使用NSThread类方法isMainThread判断当前线程是否为主线程

           {//主线程输出信息

                NSLog(@"%d now is in MainThread",nowIndex);

           }

          else

          {//非主线程输出信息

                  NSLog(@"%d now is not in MainThread",nowIndex);

           }

      }

}

该段代码输出结果如下:

2016-09-20 23:15:02.010 MultiThreadExample[634:16310] 1 now is not in MainThread

2016-09-20 23:15:03.016 MultiThreadExample[634:16310] 2 now is not in MainThread

2016-09-20 23:15:04.018 MultiThreadExample[634:16310] 3 now is not in MainThread

2016-09-20 23:15:05.021 MultiThreadExample[634:16310] 4 now is not in MainThread

2016-09-20 23:15:06.022 MultiThreadExample[634:16310] 5 now is not in MainThread

2016-09-20 23:15:07.023 MultiThreadExample[634:16310] 6 now is not in MainThread

2016-09-20 23:15:08.024 MultiThreadExample[634:16310] 7 now is not in MainThread

2016-09-20 23:15:09.025 MultiThreadExample[634:16310] 8 now is not in MainThread

2016-09-20 23:15:10.026 MultiThreadExample[634:16310] 9 now is not in MainThread

………

如果不强行终止程序,该线程会一直执行下去,数字编码也会从1开始一直不断增大。

还有一点我们在线程中使用[NSThreadsleepForTimeInterval:1];方法每次循环开始时让线程暂停1秒钟,大家一定要注意,在这种循环执行的线程中,一定要设置循环停止时间,否则线程不断死循环就会将设备CPU彻底占用,如果你运行的设备是双核CPU,你启动一个不设置循环停止时间的线程,就会直接将其中一个CPU全部沾满卡死。

从上述输出结果中也可以看到,每次输出间隔时间都是1秒钟。也就是说该循环执行的内容每隔1秒执行一次。

3.终止一个线程

停止一个线程有很多方法,初学者常犯的一个错误就是调用NSThread类的cancel方法。时机调用该方法并没有作用,该方法中设置的cancel只是一个标记位,调用cancel方法之后,再通过iscancel方法获取该标记位就可以得到是否已经cancel,真正的cancel需要在该线程的执行方法体中调用类方法exit来真正退出该线程。

- (void)viewDidLoad 

{

      [super viewDidLoad];//进入某个viewController时启动一个线程

      //使用已经写好的线程执行方法FunctionForNSThread初始化一个NSThread类对象

      NSThread* nowTestThread = [[NSThread alloc] initWithTarget:self selector:@selector(FunctionForNSThread) object:nil];

      //启动该线程类对象

      [nowTestThread start];

      [NSThread sleepForTimeInterval:10];//主线程暂停执行10秒钟,这里测试需要,一般不建议暂停主线程。

      [nowTestThread cancel];

}

- (void)FunctionForNSThread

{

      intnowIndex =0;

      while(YES)//while循环执行

      {

            nowIndex++;

            [NSThread sleepForTimeInterval:1];//每次执行到这里让线程暂停1秒钟

            if([NSThread isMainThread])//使用NSThread类方法isMainThread判断当前线程是否为主线程

            {//主线程输出信息

                 NSLog(@"%d now is in MainThread",nowIndex);

            }

            else

            {//非主线程输出信息

                 NSLog(@"%d now is not in MainThread",nowIndex);

            }

           if([[NSThread currentThread] isCancelled])//先通过currentThread方法获取当前线程,再通过isCancelled方法获取cancel标志位

           {

                 NSLog(@"退出线程之前");

                 [NSThread exit];//cancel标志位为真,说明线程外部已经发出了终止线程的标志信号,在本线程调用exit停止线程。

                 NSLog(@"退出线程之后");//该log永远不会被打印,因为在exit方法之后的代码都不会再执行

           }

      }

}

该段代码执行结果如下:

2016-09-20 23:28:37.258 MultiThreadExample[675:21235] 1 now is not in MainThread

2016-09-20 23:28:38.265 MultiThreadExample[675:21235] 2 now is not in MainThread

2016-09-20 23:28:39.267 MultiThreadExample[675:21235] 3 now is not in MainThread

2016-09-20 23:28:40.272 MultiThreadExample[675:21235] 4 now is not in MainThread

2016-09-20 23:28:41.277 MultiThreadExample[675:21235] 5 now is not in MainThread

2016-09-20 23:28:42.281 MultiThreadExample[675:21235] 6 now is not in MainThread

2016-09-20 23:28:43.283 MultiThreadExample[675:21235] 7 now is not in MainThread

2016-09-20 23:28:44.288 MultiThreadExample[675:21235] 8 now is not in MainThread

2016-09-20 23:28:45.294 MultiThreadExample[675:21235] 9 now is not in MainThread

2016-09-20 23:28:46.312 MultiThreadExample[675:21235] 10 now is not in MainThread

2016-09-20 23:28:46.312 MultiThreadExample[675:21235]退出线程之前

因为主线程在暂停10秒之后将之前启动的线程cancel标志置为YES,而在线程内部每次循环都会判断cancel标志位,如果为真就调用exit退出线程,而每次循环间隔为1秒,所以执行10次之后线程就退出了。

另外exit之后的代码都不会被执行,所以“退出线程之后”log没有打印。

以上就是IOS多线程实现方案之一 NSThread的相关内容,如果大家有什么心得或者不同见解可以找我沟通,QQ 1828141617   邮箱 yimaoruanjian@126.com

上一篇下一篇

猜你喜欢

热点阅读