笔记-iOS中级教程多线程

2020-03-18  本文已影响0人  lotus_yoma

资料来源:腾讯课堂=>《[iOS]iOS中级教程多线程》

09 __bridge

pthread_t pthread;

//char *name = "zs";
//int result = pthread_create(&pthread, NULL, demo, name);

//------使用OC语言
NSString *name = @"zs";
//__bridge 桥接
//MRC中内存管理原则:谁申请,水释放
//ARC中自动给OC对象,添加retain release autorelease
//把OC中的对象传给c语言的函数,要桥接;同样的,把c语言的参数传给OC也要桥接
int result = pthread_create(&pthread, NULL, demo, (__bridge void *)(name));
//demo函数
void * (*demo)(void * param){
NSString *name = (__bridge NSString *)param;
//NSLog(@"hello %s, %@", param, [NSThread currentThread]);
NSLog(@"hello %@, %@", name, [NSThread currentThread]);
}

__bridge告诉函数pthread_create,在ARC中传入的参数name需要函数来负责release

10 NSThread

3种创建方式:

//方法一:需要调用start方法开启线程
NSThread *thread = [[NSThread alloc] initWithTarget: self selector: @selector(demo) object: nil];
[thread start];
//方法二:类方法
[NSThread detachNewThreadSelector: @selector(demo) toTarget: self withObject: nil];
//方法三:严格来说不算是NSThread方法
[self performSelectorInBackground: @selector(demo) withObject: nil];

11 线程状态

//当线程结束之后,不能再次使用

//新建状态
NSThread *thread = [[NSThread alloc] initWithTarget: self selector: @selector(demo) object: nil];
//就绪状态
[thread start];

-(void)demo{
  for (int i = 0; i < 20; i ++){
    NSLog(@"%d", i);
    if (i == 5){
      //阻塞状态
      [NSThread sleepForTimeInterval: 3];
    }
    if (i == 10){
      //线程退出 死亡状态
      [NSThread exit];
    }
  }
}

12 线程属性

NSThread *thread = [[NSThread alloc] initWithTarget: self selector: @selector(demo) object: nil];
//线程名称
thread.name = @"t1";
//线程优先级,0-1.0,default:0.5
//内核调度算法在决定该运行哪个线程时,会把线程的优先级作为考量因素,较高优先级的线程会比较低优先级的线程具有更多的运行机会。较高优先级不保证你的线程具体执行的时间,只是相比较低优先级的线程它更有可能被调度器选择执行而已。
//即无法保证thread执行完再执行其他线程
thread.threadPriority = 1.0;
[thread start];

15 互斥锁

//任意一个对象内部都有一把锁,锁默认是打开的
//加锁会影响程序的性能

//互斥锁
//线程同步
/*
NSObject *obj = [NSObject new];
@synchronized(obj){
  //此时,使用obj局部变量的话,thread1进来默认objc的锁是打开的,程序可以继续进行;然后thread2进来,又重新初始化了一个objc,锁默认也是打开的,因此程序也可继续进行,无法达到加锁的效果;
  //改进办法:将objc设置成全局变量或者属性
}
*/
//用的是self的锁
@synchronized(self){
  if (self.ticketsCount > 0)
    self.ticketsCount --;
}else{
  NSLog(@"来晚啦,票没了");
}

互斥锁使用:@synchronize(锁对象){//需要锁定的代码}

互斥锁:能有效防止因多线程抢夺资源造成的数据安全问题

线程同步的意思是:多条线程按顺序地执行任务。互斥锁就是使用了线程同步技术


16 原子属性

属性中的修饰符:

17 互斥锁和自旋锁的区别

互斥锁:如果发现其他线程正在执行锁定代码,线程会进入休眠(就绪状态),等其他线程时间片到打开锁后,线程会被唤醒(执行)

自旋锁:如果发现有其他线程正在锁定代码,线程会用死循环的方式,一直等待锁定的代码执行完成,自旋锁更适合执行不耗时的代码。一般就用在属性中。

线程安全:线程同时操作时不安全的,多个线程同时操作一个全局变量。线程安全,即是在多个贤臣进行读写操作时,仍然能够保证数据的正确。

主线程(UI线程):

18 异步下载网络图片

-(void)loadView
{
    //初始化scrollView,并赋值给当前vc的view
    self.scrollView = [[UIScrollView alloc] initWithFrame: [UIScreen mainScreen].bounds];
    self.scrollView.backgroundColor = [UIColor whiteColor];
    self.view = self.scrollView;
    //初始化imageView
    self.imageView = [[UIImageView alloc] init];
    [self.scrollView addSubview: self.imageView];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSThread *thread = [[NSThread alloc] initWithTarget: self selector: @selector(downloadImage) object: nil];
    [thread start];
}

-(void)downloadImage
{
    NSData *data = [NSData dataWithContentsOfURL: [NSURL URLWithString: @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1583403375529&di=765d6a01b4b7a5183862ad886f5a2f5d&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2017-11-29%2F5a1e130e127ef.jpg"]];
    UIImage *image = [UIImage imageWithData: data];
    
    //在主线程上更新UI控件  线程间通信
    //waitUntilDone 值是YES 会等待方法执行完毕,才会执行后续代码
    [self performSelectorOnMainThread: @selector(updateUI:) withObject: image waitUntilDone: YES];
    
}

-(void)updateUI: (UIImage *)image
{
    self.imageView.image = image;
    //    self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
    //让imageView的大小和图片一致
    [self.imageView sizeToFit];
    //设置scrollView的滚动范围
    self.scrollView.contentSize = image.size;
}

19 strong和weak

什么时候用strong和weak

示例:

创建ZYPerson类,整体工程是ARC模式的,设置ZYPerson为MRC

那么,秉持谁申请谁释放的原则,将person放入自动释放池,延迟释放。

+(instancetype)personWithName:(NSString *)name
{
    ZYPerson *person = [[ZYPerson new] autorelease];
    person.name = name;
    return person;
}

在vc中绑定属性,特地设置为weak

@property (nonatomic, weak) ZYPerson *p1;
@property (nonatomic, weak) ZYPerson *p2;

viewDidLoad中初始化p1和p2属性

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.p1 = [[ZYPerson alloc] init];
    self.p1.name = @"zs";
    NSLog(@"p1: %@", self.p1.name);
    
    self.p2 = [ZYPerson personWithName: @"ls"];
    NSLog(@"p2: %@", self.p2.name);
}

结果为:


原因:p2采用的初始化方法中,自动释放池对p2有强引用,因此可以打印出ls。在viewDidLoad()结束后自动释放池销毁时,p2也就release了。因此如果在其他方法中再次调用self.p2.name也会得到null的结果。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"p1: %@", self.p1.name);
    NSLog(@"p2: %@", self.p2.name);
}

20 自动释放池

iOS开放中的内存管理:

自动释放池:

每一次主线程的消息循环开始的时候,系统会先创建自动释放池,消息循环结束前,会释放自动释放池。消息循环(the event loop)是用来处理事件的。

自动释放池和线程的关系,其实是因为消息循环和线程有关。

示例中viewDidLoad()方法中的是在application:didFinishLaunchingWithOptions事件里执行的,因此自动释放池也是在此事件中创建和释放的。

什么时候使用自动释放池:

21 自动释放池面试题

for (int i = 0; i < 100000000;i ++){
  @autoreleasepool{
      NSString *str = [[NSString alloc] initWithFormat: @"%d", i];
  }
}

加上自动释放池后,内存几乎不涨。

22 属性的修饰符

属性修饰符:

retain: MRC中使用

strong: ARC中使用

weak: 只有ARC下才能用

assign: ARC和MRC都可以使用

copy:ARC和MRC都可以使用

上一篇 下一篇

猜你喜欢

热点阅读