线程间的通信
 
简单说明
线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信
 
线程间通信的体现
1个线程传递数据给另1个线程
在1个线程中执行完特定任务后,转到另1个线程继续执行任务
 
线程间通信常用方法

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

线程间通信示例 – 图片下载

2015111892145343.png (600×346)

//

//  YYViewController.m

//  06-NSThread04-线程间通信

//

//  Created by apple on 14-6-23.

//  Copyright (c) 2014年 itcase. All rights reserved.

//
#import "YYViewController.h"

@interface YYViewController ()

@property (weak, nonatomic) IBOutlet UIImageView *iconView;

@end

@implementation YYViewController
- (void)viewDidLoad

{

    [super viewDidLoad];

}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{
// 在子线程中调用download方法下载图片

    [self performSelectorInBackground:@selector(download) withObject:nil];

}
 
-(void)download

{

    //1.根据URL下载图片

    //从网络中下载图片

    NSURL *urlstr=[NSURL URLWithString:@"fdsf"];
    //把图片转换为二进制的数据

    NSData *data=[NSData dataWithContentsOfURL:urlstr];//这一行操作会比较耗时
    //把数据转换成图片

    UIImage *image=[UIImage imageWithData:data];

 

    //2.回到主线程中设置图片

    [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];

}
 
//设置显示图片

-(void)settingImage:(UIImage *)image

{

    self.iconView.image=image;

}
@end

代码2:
//

//  YYViewController.m

//  06-NSThread04-线程间通信

//

//  Created by apple on 14-6-23.

//  Copyright (c) 2014年 itcase. All rights reserved.

//
#import "YYViewController.h"

#import 
@interface YYViewController ()

@property (weak, nonatomic) IBOutlet UIImageView *iconView;

@end

@implementation YYViewController
- (void)viewDidLoad

{

    [super viewDidLoad];

}
 

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

// 在子线程中调用download方法下载图片
    [self performSelectorInBackground:@selector(download) withObject:nil];

}
 

-(void)download

{
    //1.根据URL下载图片

    //从网络中下载图片

    NSURL *urlstr=[NSURL URLWithString:@"fdsf"];
    //把图片转换为二进制的数据

    NSData *data=[NSData dataWithContentsOfURL:urlstr];//这一行操作会比较耗时
    //把数据转换成图片

    UIImage *image=[UIImage imageWithData:data];
    //2.回到主线程中设置图片

    //第一种方式

//    [self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
    //第二种方式

    //    [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
    //第三种方式

   [self.iconView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];

}


//设置显示图片

//-(void)settingImage:(UIImage *)image

//{

//    self.iconView.image=image;

//}
@end

线程安全
 
一、多线程的安全隐患
资源共享
1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源
比如多个线程访问同一个对象、同一个变量、同一个文件
当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题
示例一:

2015111892251282.png (664×387)

示例二:

2015111892312267.png (659×386)

问题代码:

//

//  YYViewController.m

//  05-线程安全

//

//  Created by apple on 14-6-23.

//  Copyright (c) 2014年 itcase. All rights reserved.

//


#import "YYViewController.h"
@interface YYViewController ()

//剩余票数
@property(nonatomic,assign) int leftTicketsCount;

@property(nonatomic,strong)NSThread *thread1;

@property(nonatomic,strong)NSThread *thread2;

@property(nonatomic,strong)NSThread *thread3;


@end

@implementation YYViewController


- (void)viewDidLoad

{

    [super viewDidLoad];
    //默认有20张票
    self.leftTicketsCount=10;
    //开启多个线程,模拟售票员售票
    self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread1.name=@"售票员A";
    self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread2.name=@"售票员B";
    self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

    self.thread3.name=@"售票员C";

}
 

-(void)sellTickets

{

    while (1) {

        //1.先检查票数

        int count=self.leftTicketsCount;

        if (count>0) {

            //暂停一段时间

            [NSThread sleepForTimeInterval:0.002];
            //2.票数-1

           self.leftTicketsCount= count-1;

 

            //获取当前线程

            NSThread *current=[NSThread currentThread];

            NSLog(@"%@--卖了一张票,还剩余%d张票",current,self.leftTicketsCount);

        }else

        {

            //退出线程

            [NSThread exit];

        }

    }

}


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{ 

    //开启线程
   [self.thread1 start];

    [self.thread2 start];

    [self.thread3 start];
}
@end

打印结果:

2015111892340617.png (871×448)

二、安全隐患分析

2015111892405061.png (625×320)

2015111892430149.png (678×379)

三、如何解决
 
互斥锁使用格式
@synchronized(锁对象) { // 需要锁定的代码  }
注意:锁定1份代码只用1把锁,用多把锁是无效的
 
代码示例:

//

//  YYViewController.m

//  05-线程安全

//

//  Created by apple on 14-6-23.

//  Copyright (c) 2014年 itcase. All rights reserved.

//
#import "YYViewController.h"
@interface YYViewController ()
//剩余票数

@property(nonatomic,assign) int leftTicketsCount;

@property(nonatomic,strong)NSThread *thread1;

@property(nonatomic,strong)NSThread *thread2;

@property(nonatomic,strong)NSThread *thread3;

@end
@implementation YYViewController
- (void)viewDidLoad

{

    [super viewDidLoad];

    //默认有20张票

    self.leftTicketsCount=10;

    //开启多个线程,模拟售票员售票
    self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread1.name=@"售票员A";
    self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread2.name=@"售票员B";
    self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread3.name=@"售票员C";

}


-(void)sellTickets

{

    while (1) {

        @synchronized(self){//只能加一把锁

        //1.先检查票数
        int count=self.leftTicketsCount;

        if (count>0) {

            //暂停一段时间

            [NSThread sleepForTimeInterval:0.002];

            //2.票数-1
           self.leftTicketsCount= count-1;

            //获取当前线程

            NSThread *current=[NSThread currentThread];

            NSLog(@"%@--卖了一张票,还剩余%d张票",current,self.leftTicketsCount);
        }else

        {

            //退出线程

            [NSThread exit];

        }

        }

    }

}


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{
    //开启线程

   [self.thread1 start];

    [self.thread2 start];

    [self.thread3 start];

}
@end

执行效果图

2015111892457124.png (876×191)

互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的CPU资源
 
互斥锁的使用前提:多条线程抢夺同一块资源
相关专业术语:线程同步,多条线程按顺序地执行任务
互斥锁,就是使用了线程同步技术
 
四:原子和非原子属性
 
OC在定义属性时有nonatomic和atomic两种选择
atomic:原子属性,为setter方法加锁(默认就是atomic)
nonatomic:非原子属性,不会为setter方法加锁
 
atomic加锁原理

@property (assign, atomic) int age;
- (void)setAge:(int)age

{
    @synchronized(self) { 

       _age = age;

    }

}

原子和非原子属性的选择
nonatomic和atomic对比
  • atomic:线程安全,需要消耗大量的资源
  • nonatomic:非线程安全,适合内存小的移动设备 

iOS开发的建议

  • 所有属性都声明为nonatomic
  • 尽量避免多线程抢夺同一块资源
  • 尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力

浅析iOS应用开发中线程间的通信与线程安全问题的更多相关文章

  1. 详解html5 postMessage解决跨域通信的问题

    这篇文章主要介绍了详解html5 postMessage解决跨域通信的问题的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. 详解使用postMessage解决iframe跨域通信问题

    这篇文章主要介绍了详解使用postMessage解决iframe跨域通信问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5调用手机发短信和打电话功能

    这篇文章主要介绍了HTML5调用手机发短信和打电话功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. HTML5在微信内置浏览器下右上角菜单的调整字体导致页面显示错乱的问题

    HTML5在微信内置浏览器下,在右上角菜单的调整字体导致页面显示错乱的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

  5. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  6. ios – containerURLForSecurityApplicationGroupIdentifier:在iPhone和Watch模拟器上给出不同的结果

    我使用默认的XCode模板创建了一个WatchKit应用程序.我向iOSTarget,WatchkitAppTarget和WatchkitAppExtensionTarget添加了应用程序组权利.(这是应用程序组名称:group.com.lombax.fiveminutes)然后,我尝试使用iOSApp和WatchKitExtension访问共享文件夹URL:延期:iOS应用:但是,测试NSURL

  7. ios – Testflight无法安装应用程序

    我有几个测试人员注册了testflight并连接了他们的设备……他们有不同的ios型号……但是所有这些都有同样的问题.当他们从“safari”或“testflight”应用程序本身单击应用程序的安装按钮时……达到约90%并出现错误消息…

  8. 真正的iOS设备和Watch Simulator可以进行通信以进行测试

    我想为现有的iOS应用创建一个手表应用.但我处于一种情况,我没有苹果手表,我现有的iOS应用程序只能在不在模拟器上的真实设备上运行.是否可以在iPhone设备上运行应用程序并在手表模拟器中测试我的手表应用程序?解决方法至少在目前,不可能配对真正的iPhone和Watch模拟器.我得出这个结论有三个原因:>Watch模拟器在安装过程中自动与iPhone模拟器配对.>根本无法从界面取消配对Watch模拟器.>在模拟器上无法访问蓝牙以与真实设备进行通信.这是一个proof.

  9. ibm-mobilefirst – 在iOS 7.1上获取“无法安装应用程序,因为证书无效”错误

    当我的客户端将他们的设备更新到iOS7.1,然后尝试从AppCenter更新我们的应用程序时,我收到了上述错误.经过一番搜索,我找到了一个类似问题的帖子here.但是后来因为我在客户端使用AppCenter更新应用程序的环境中,我无法使用USB插件并为他们安装应用程序.在发布支持之前,是否有通过AppCenter进行下载的解决方法?

  10. ios – 视图的简单拖放?

    我正在学习iOS,但我找不到如何向UIView添加拖放行为.我试过了:它说“UIView没有可见的接口声明选择器addTarget”此外,我尝试添加平移手势识别器,但不确定这是否是我需要的它被称为,但不知道如何获得事件的坐标.在iOS中注册移动事件回调/拖放操作的标准简单方法是什么?

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部