iOS开发之笔记摘录

OC基础快速恢复2

2017-11-18  本文已影响3440人  平安喜乐698
目录
    知识点  
        1.类别和扩展
        2.@修饰符
        3.const ,  #define ,  typedef,extern,static
        4.野指针和空指针的区别
        5.self.name和_name的区别
        6.id与instancetype与void *的区别
        7.nil、Nil、Null、NSNull的区别
        8.#include 和 #import 的区别
        9.循环引用
    单例
    多线程
    block
    KVC
    KVO
    内存管理机制
    Category
    架构模式
0. 知识点
  1. 类别和扩展
类别 Category
    只能添加方法,不能添加属性(因为添加属性时,不会自动生成set、get方法。可使用runtime动态运行时机制来添加,但只有在运行时才存在)
    级别高于普通类,会覆盖普通类中同名的方法(因为先编译普通类,再编译类别)。若两个类别都实现了,则决定于头文件的添加顺序(排在下边的优先级高)。

扩展
    只存在于.m文件中.    
    @interface Person(){
        NSString *name;
    }
    @property (nonatomic,readwrite) NSArray *contentArray; 
    -(void)run; 
    @end
  1. @修饰符
@property修饰符
例:
     @property (nonatomic,strong) NSArray *contentArray; 

“访线指引”
     访问权限相关   :readwrite、readonly
     线程安全相关   :nonatomic、atomic(注意不写时:默认为atomic。原子性:一个操作要么执行要么不执行且执行中不会被打断,使用自旋锁不允许多线程同一时间访问,耗资源降低性能,且不一定线程安全。只会对set上锁,get没必要)
     指定方法名     :setter=、getter=
     引用计数相关   :copy、assign、weak、strong、retain
默认:(readwrite,assign, atomic)

     copy
     NSString/NSDictionary/NSArray使用copy,而不是strong(将NSMutableArray对象赋值给NSArray后,修改前者,后者内容也变了。)    block使用copy,将block的值从栈区复制到堆区,改变block的作用域
     assign   :直接赋值(修饰基本数据类型、结构体、枚举---非类类型)
     weak     :弱引用,引用计数不+1  (仅修饰类类型,防止循环引用)(dele避免循环引用造成内存泄漏;控件---VC强引用self.view强引用subViews数组强引用控件,所以可以使用weak修饰)
     strong   :强引用,引用计数+1(仅修饰类类型,除了NSArray/NSDictionary/NSArray/.../block外的类类型)


深拷贝/浅拷贝
     深拷贝:拷贝对象的值
     浅拷贝:拷贝对象的指针
     copy出来的对象:不可变。      (copy不可变类型:浅拷贝,copy可变类型:深拷贝)
     mutableCopy出来的对象:可变。 (永远都是深拷贝)   
     错误观点:copy是浅拷贝,mutableCopy是深拷贝。  当用copy可变数组时

不完全拷贝/ 完全拷贝
     不完全拷贝(默认,拷贝的内容中元素是类类型,则只拷贝该元素的指针)  
      完全拷贝(需要覆写copyWithZone:手动返回新实例)
修饰属性和方法的使用范围
    @public      : 所有地方都能使用
    @private     : 仅本类可用
    @protected   : 本类及子类
    @package     : 本应用程序包

修饰协议中方法
    @optional    : 协议可选实现方法
    @required    : 协议必须实现方法

修饰属性
    @dynamic 属性;
      其getter和setter方法编译器是不会自动生成,需手动实现,否则使用时崩溃.
    @synthesize 属性;(默认情况下编译器自动生成)
      其getter和setter方法编译器是会自动生成,不需手动实现。

修饰类
    @class 类名;
    作用:用于在.h中提前声明一个类,提高编译效率;.m依旧要引入该类#import""
  1. const , #define , typedef,extern,static
const    用来定义一个常量(存放在常量表中,编译时检查数据类型)
      const int a=10; int const a=10;   const与数据类型互换无影响
      const Person *p; *p不可变  p可变      Person *const p;  p不可变  *p可变

#define  
    宏定义(预编译指令,预处理阶段直接替换,不存在于常量表中),将前者替换成后者,编译时不检查数据类型
    #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
typdedef 
    给已有类型起别名(1.便捷:枚举,结构体,block;2.安全:给系统类型重命名),检查数据类型
    typedef int MyIn;  // typedef 旧 新;
extern   
    修饰全局变量且没有用static修饰时,其作用域为整个项目文件
    // 定义
    int gAge =10;
     // 其他文件中获取
    extern int gAge; 
    NSLog(@"%d", gAge);
static
      修饰局部变量时:程序运行期间只会初始化一次 并且 直到整个程序结束时才被销毁
      static int age = 20;
      修饰全局变量时:作用域仅限于本类



比较
     const和#define都可以定义常量,区别:
         处理时间不同:#define预编译阶段(编译之前),const编译阶段
         #define不能进行类型检测,const可以
         #define可以定义函数,const只能定义常量
         大量#define会造成编译时间过长

     typdedef与#define的区别
          typedef会对语法进行检测,#define直接替换
使用

应用的所有地址
方法1:新建.h文件(需要在pch中导入)
    在.h中 
    // 开发中的API_URL使用(避免此文件外被改动)
    static  NSString * const loginURL = @"/login";
    // 以下在这里错误,loginURL依然可以被改成其他值
    static  NSString const * loginURL = @"/login";
方法2:新建.h.m文件(需要在pch中导入)
    在.h中 
    extern NSString * const loginURL;
    在.m中 
    NSString * const loginURL = @"name";
  1. 野指针和空指针的区别
野指针和空指针的区别
    野指针:
        指针指向了一个被释放的对象(僵尸对象,造成的原因:过多地release对象)(所指向的地址有个“标识”:标识此为僵尸对象)
        只要给野指针发送消息,程序就会报错(为了避免,对象释放后,设置为nil)。
    
    空指针:
        指针指向nil(指针设置为nil)。
        给空指针发送消息不会报错。[nil Method];    // 不会崩
  1. self.name和_name的区别
self.name和_name的区别:
    self.name会调用setget方法修改变量,而_name会直接修改变量。

self.name=nil和[self.name release]的区别:
    self.name是通过set方法将name属性置为nil,[name release] 只是将name的引用计数减1,此时若name的引用计数不为0,还可以访问。
  1. id与instancetype与void *的区别
id与instancetype与void *的区别:
    id可以指向任何类型的对象(不需要*)
    instanceType只能作为返回值返回和该方法所在类相同类型的对象
    void*指无类型指针(等同于id),指向任意类型的对象
  1. nil、Nil、Null、NSNull的区别
nil、Nil、Null、NSNull的区别:
    nil    :表示空对象,调用nil不会崩溃
    Nil    :表示空类
    Null   :表示空指针,不指向任何内存地址
    NSNULL :表示一个空的集合对象

8.#include 和 #import 的区别

#include 不能(会多次导入)
#import 不会重复导入头文件
    #import<> 包含系统头文件(从系统库目录中查找)
    #import"" 包含自定义头文件(查找自定义头文件)

  1. 循环引用
block
    当block作为属性(copy),且block内部引用self,造成循环引用。
    解决:
    __weak BViewController *weakSelf = self;
    self.block = ^{
        NSLog(@"%@",weakSelf.name); 
    };

NSTimer
    当timer作为属性,且设置self为target,造成循环引用
    解决:使用weak修饰

delegate
    当B是A的属性,且B的delegate属性是A,造成循环引用
    解决:
    delegate属性用weak修饰
    NSObject
        +(void)initialize{[super initialize];}
        第一次使用该类时调用(会在init方法前调用)(类别优先级高)
        +(void)load{}
        应用启动后会 加载所有类的load方法(最先,会在main之前)(类别优先级高)
延迟加载:
    重写get方法,用到时才加载
    避免瞬时内存过高
异步加载:
    避免线程堵塞

delegate

// dele使用weak:为了避免循环引用
@property (nonatomic,weak) id delegate;


例:
UITableView的delegate和dataSource都是代理
  delegate提供交互
  dataSource提供数据源
代理和block的区别:
    相同点:都能传递值;都应避免循环引用;都应在使用前判断是否实现;
    不同点:代理需要创建协议,用weak修饰dele属性,实现dele方法。block用copy修饰
View
    // 构造(初始化)
    -(instancetype)init{}   
    -(instancetype)initWithFrame:(CGRect)frame;
    -(void)delloc{};        // 销毁

指针

     int a[10];           // 10个int 元素
     int *a[10];          // 10个指向int的指针 元素
     int (*a)[10];        // 指向10个int元素数组 指针
     int (*a[10])(int);   // 10个指向函数(返回int参数int)的指针 元素
1. 单例
单例
  程序运行期间(从点击App开始运行到关掉App结束运行),该类只会创建一个实例(对象指针存在于静态区,对象在堆中所占的空间 只会在程序终止后才会被释放)。
                                 使用

YTAccount.h

#import <Foundation/Foundation.h>
@interface YTAccount : NSObject<NSCopying,NSMutableCopying>
+(instancetype)sharedAccount;
@end

YTAccount.m

#import "YTAccount.h"

@implementation YTAccount
static YTAccount *_sharedAccount;

// 用于外部访问
+(instancetype)sharedAccount{
    return [self new];
}


// 调用alloc会调用本方法(若不实现,用allocWithZone多次创建对象得到的不是单例)
+(instancetype)allocWithZone:(struct _NSZone *)zone{
/*
// 方法一
    // 线程锁(防止多线程同时调用)
    @synchronized (self) {
        if(!_sharedAccount){
            _sharedAccount=[super allocWithZone:zone];
        }
    }
    return _sharedAccount;
*/
    
// 方法二
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //
        if(!_sharedAccount){
        
            _sharedAccount=[super allocWithZone:zone];
        }
    });
    return _sharedAccount;
}

// 避免使用copy mutableCopy方法时再次创建
-(id)copyWithZone:(NSZone *)zone{
    return _sharedAccount;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
    return _sharedAccount;
}
@end
                             优化使用(方案一)

放在pch中

#define shareH(name) +(instancetype)share##name;

#if __has_feature(objc_arc)

#define shareM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}
#else
#define singleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
\
+(instancetype)share##name\
{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
return _instance;\
}\
-(oneway void)release\
{\
}\
\
-(instancetype)retain\
{\
return _instance;\
}\
\
-(NSUInteger)retainCount\
{\
return MAXFLOAT;\
}
#endif

使用

  .h中  shareH(类名)
  .m中  shareM(类名)
                             优化使用(方案二)
实现一个单例基类
需要单例时继承即可
2. 多线程

2.1 概念

程序、进程、线程、多线程
    启动一个应用程序后,会至少创建一个进程,该进程会创建一个主线程。

进程

1、简介
 (1)一个进程是指在系统中正在运行的一个应用程序。
 (2)进程间相互独立,每个进程均运行在其专用且受保护的内容空间内。
 (3)通过“活动监视器”可以查看mac系统中所开启的进程。
2、进程通信
 单机系统中进程通信有四种形式:主从式、会话式、消息或邮箱机制、共享存储区方式。
    主从式例子:终端控制进程和终端进程。
    会话式例子:用户进程与磁盘管理进程之间的通信。

线程

简介
(1)线程(Thread),也称作轻量级进程。线程是进程的组成部分,一个进程可以拥有多个线程(至少有一个主线程)。
(2)线程在程序中是独立的、并发的执行流,当进程被初始化后,主线程就被创建了。
(3)可以在进程内创建多条顺序执行流,这些顺序执行流就是线程,每条线程是相互独立的。
(4)线程是独立运行的,单个线程他是不知道进程中是否存在其他的线程,线程的执行是抢占式的。(当前运行的线程在任何时候都可能被挂起,以便另外一个线程可以运行)。
(5)3个基本状态:就绪,执行,阻塞
(6)一个进程要想执行任务,必须得有线程(每一个进程至少要有一条线程,可以有多个线程)。
(7)线程是进程的基本执行的单元,一个进程(程序)的所有的任务都在线程中执行。
(8)一个线程中的任务的执行是串行的。(如果要在一个线程中执行多个任务,那么只能一个一个地按照顺序执行这些任务)。
(9)在同一时间内,一个线程只能执行一个任务。

多线程

1、简介
 (1)一个进程中可以开启多条线程,每条线程可以并行(同时)执行不同的任务。
 (2)多线程技术可以提高程序的执行效率。
 
2、原理
 (1)同一时间,CPU只能处理一条线程,只有一条线程在工作(执行)。
 (2)多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)。
 (3)如果CPU调度线程的时间足够快,就会造成了多个线程并发执行的假象。
 (4)如果线程非常多,CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源,每条线程被调用执行的频次会降低(线程的执行效率降低)。
 
3、优缺点
优点:
    适当提高程序的执行效率、资源利用率(CPU、内存利用率)。
 (1)对于单线程的应用而言,整个应用只有一个顺序执行流,当执行流在某个耗时操作或不能立即完成的任务时(如网络请求、复杂的操作和运行过程、某些必须消耗一定时间后才能完成的操作),该执行流就会被阻塞,整个应用就会被卡在那里无法继续执行,因此单线程的程序往往功能非常有限。
 (2)在实际应用中多线程是非常有用的,例如:用户操作界面上的某个按钮时,该按钮需要执行的任务需要几秒甚至十几秒,如果直接在UI线程(主线程)中完成这个任务,在该任务执行完成、返回之间,UI线程被该任务阻塞,无法响应用户的其他操作(这段时间内,用户对iOS系统的操作将不会有任何反应,除非用户单机Home键返回,但这并不是用户希望的结果)。
缺点:
 (1)开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能。
 (2)线程越多,CPU在调度线程上的开销就越大。
 (3)程序设计更加复杂:如线程之间的通信,多线程的数据共享。
 
4、在iOS开发中的应用
    一个iOS程序运行后,默认会开启1条线程,称为主线程(UI线程)。
    主线程用来
        1、显示、刷新UI界面
        2、处理UI事件(点击事件、滚动事件、拖曳事件等)。
        3、比较耗时的操作不要放在主线程中。耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种卡的坏的体验。
多线程资源共享的安全隐患
        一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源。当多个线程访问同一资源时,很容易引发数据散乱和数据安全问题。(如多个线程访问同一个对象、同一个变量、同一个文件)。

解决方法:使用互斥锁
        使用的格式:@synchronized(锁对象){//需要锁定的代码}     注:锁定一份代码只用一把锁,用多吧锁是无效的。
    互斥锁的优点
        能有效防止因多线程抢夺资源造成的数据安全问题
    互斥锁的缺点
        需要消耗大量的CPU资源。
    互斥锁的使用前提
        多条线程抢夺同一块资源。(互斥锁就是使用了线程同步技术,多条线程按顺序地执行任务)。

示例:在创建单例模式时,最好使用互斥锁。
 static UserInfo *singletonUserInfo = nil;
 +(UserInfo *)shareUserInfo{
 @synchronized(self){
 //创建一个线程锁,防止多线程中多次创建
 if (singletonUserInfo == nil) {
 singletonUserInfo = [[UserInfo alloc]init];
 NSLog(@"初始化");
 }
 }
 return singletonUserInfo;
 }


atomic
    原子性,为setter方法加锁(默认就是atomic),线程安全,需要消耗大量的资源
nonatomic
    非原子性,不会为setter方法加锁,非线程安全,适合内存小的移动设备
 iOS开发:最好所有属性都声明为nonatomic,尽量避免多线程抢夺同一块资源,尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力。

简单总结

 1.一个程序至少有一个进程,一个进程至少有一个线程。
    进程创建则主线程创建。
    主线程死掉则进程死掉。
 2.进程是最小的资源分配单位,线程是最小的CPU执行单位。
    进程之间相互独立,且所有任务都交由线程去执行。
    多个线程之间相互独立,但共享同一进程的资源。
 3.更新UI要放在主线程中(否则:防止造成卡顿,避免多个子线程同时操作UI)
同步/异步/串行/并行

 同步:任务块完成后再继续向下执行
 异步:跳过任务块继续向下执行
 串行:是指一个队列,队列中的任务依次执行
 并行:是指一个队列,队列中的任务同时执行
 
 4种(首先先考虑队列,再考虑同异步)
   同步串行(死锁)
   同步并行
   异步串行
   异步并行

2.2 使用

NSThread

创建线程
(方式一)(创建后调用start启动)
    NSThread *thread=[[NSThread alloc]initWithTarget:self selector:@selector(method:) object:@""];
(方式二)(创建后调用start启动)
    NSThread *thread1=[[NSThread alloc]initWithBlock:^{
    }];
(方式三)(创建后自动启动)
    [NSThread detachNewThreadSelector:@selector(method:) toTarget:self withObject:@""];
(方式四)(创建后自动启动)
    [NSThread detachNewThreadWithBlock:^{
    }];
(方式五)(隐式创建)
    //
    [self performSelector:@selector(method)];
    [self performSelector:@selector(method) withObject:nil];
    [self performSelector:@selector(method) withObject:nil withObject:nil];
    [self performSelector:@selector(method) withObject:nil afterDelay:1.0];
    [self performSelector:@selector(method) withObject:nil afterDelay:1.0 inModes:@[NSRunLoopCommonModes]];
    //
    [self performSelector:@selector(method) onThread:thread withObject:nil waitUntilDone:true];
    [self performSelector:@selector(method) onThread:thread withObject:nil waitUntilDone:true modes:@[NSRunLoopCommonModes]];
    //
    [self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:true];
    [self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:true modes:@[NSRunLoopCommonModes]];
    //
    [self performSelectorInBackground:@selector(method) withObject:nil];
thread实例方法

    // 是否是主线程
    BOOL isMain=[thread isMainThread];
    // 是否被取消
    BOOL isCanceled=[thread isCancelled];
    // 是否正在执行
    BOOL isExecuting=[thread isExecuting];
    // 是否已结束
    BOOL isFinished=[thread isFinished];
    // 是否是主线程
    BOOL isMainThread=[thread isMainThread];

    // 获取线程名
    NSString *threadName=thread.name;
    // 设置线程名
    [thread setName:@"name"];
    // start
    [thread start];
    // cancel
    [thread cancel];

    // 获取所占的栈区大小
    NSUInteger *size=[thread stackSize];
    // 设置所占的栈区大小
    [thread setStackSize:1024*5];

    // 获取优先级
    double x=thread.threadPriority;
    // 设置优先级
    [thread setThreadPriority:1000];
NSThread类方法

    // 获取当前线程
    NSThread *currentThread=[NSThread currentThread];
    // 杀死当前线程
    [NSThread exit];
    // 阻塞当前线程10s
    [NSThread sleepForTimeInterval:10];
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    // 判断当前线程是否多线程
    BOOL isMutiThread=[NSThread isMultiThreaded];

    // 获取主线程
    NSThread *mainThread=[NSThread mainThread];
    // 判断当前线程是否是主线程
    BOOL isMainThread=[NSThread isMainThread];

    // 获取当前线程的调度优先级
    // 调度优先级的取值范围是0.0~1.0,默认0.5,值越大,优先级越高。
    double priority=[NSThread threadPriority];
    // 设置调度优先级
    [NSThread setThreadPriority:0.5];
    // 即将进入多线程模式
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(willBecomeMuti:) name:NSWillBecomeMultiThreadedNotification object:nil];
    // 进入单线程模式
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(becomeSigle:) name:NSDidBecomeSingleThreadedNotification object:nil];
    // 线程退出
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(willExit:) name:NSThreadWillExitNotification object:nil];

GCD

同步/异步/主线程/全局线程
    // 同步  1.主线程(串行)
    dispatch_sync(dispatch_get_main_queue(), ^{
    });
    // 异步  2.全局线程(并行)
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    });
自定义线程队列    
    // 串行
    dispatch_queue_t queue=dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    // 并行
    dispatch_queue_t queue2=dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);


延迟
    // 延迟2s执行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*2), dispatch_get_main_queue(), ^{
    });
    
重复
    // 重复3次执行
    dispatch_apply(3, dispatch_get_main_queue(), ^(size_t x) {
    });
    
onlyOne    
    // 仅执行一次
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        //
    });
    

组    dispatch_group_t
    //
    dispatch_queue_t dispatchQueue = dispatch_queue_create("ted.queue.next", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group=dispatch_group_create();
    dispatch_group_async(group, dispatchQueue, ^{
    });
    // group内所有队列完成后调用
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    });


同步锁
    // dispatch_semaphore_t 信号量:用于同步
    // 1.创建信号量(个数>=0)  (放在代码块上)
    dispatch_semaphore_t semaphore=dispatch_semaphore_create(0);
    // 2.信号量个数+1          (放在代码块中)
    dispatch_semaphore_signal(semaphore);
    // 3. 等待直到信号量个数>0   (放在代码块下)
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    // 3. 10s内等待直到信号量个数>0
    dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 10));

    
同步锁
    // dispatch_group_t同步
    dispatch_group_t group=dispatch_group_create();
    // 进入组
    dispatch_group_enter(group);
    dispatch_group_async(group, dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT), ^{
        // 离开组
        dispatch_group_leave(group);
    });
    // 等待直到离开组
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);


栅栏
    // dispatch_barrier_async先并发执行栅栏之前任务,在执行栅栏任务,在并发执行栅栏后的任务
    dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-1");
    });
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-2");
    });
    dispatch_barrier_async(concurrentQueue, ^(){
        NSLog(@"dispatch-barrier");
    });
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-3");
    });
    dispatch_async(concurrentQueue, ^(){
        NSLog(@"dispatch-4");
    });

NSOperation

NSOperation是对GCD的封装,相比GCD,NSOperation能处理大量的并发请求,更好的处理队列之间的依赖关系,缺点是比GCD稍慢效率低.
    // 1.创建queue队列
    NSOperationQueue *optionQueue=[NSOperationQueue new];
    // 1.1设置queue最大并行数
    [optionQueue setMaxConcurrentOperationCount:5];
    
    // 2.添加blockOption到queue
    // 创建option 
    NSBlockOperation *option=[NSBlockOperation blockOperationWithBlock:^{
    }];
    // 设置option代码块完成时调用
    [option setCompletionBlock:^{
    }];
    // 添加option到queue
    [optionQueue addOperation:option];

    // 2.1 option添加依赖(option2完成后才能执行option1)
    NSBlockOperation *option2=[NSBlockOperation blockOperationWithBlock:^{
    }];
    [option addDependency:option2];
    // 删除依赖
    [option removeDependency:option2];

    // 2.添加blockOption到queue(匿名)
    [optionQueue addOperationWithBlock:^{
    }];  


    // 2. 添加InvocationOperation到queue
    NSInvocationOperation *option=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(method) object:nil];
    // 添加option到queue
    [optionQueue addOperation:option];


    // 2. 添加option数组
    [optionQueue addOperations:@[] waitUntilFinished:true];
queue 队列方法

    // 获取 option数量(readOnly)
    NSUInteger operationCount=optionQueue.operationCount;
    // 获取 最大option数量
    NSInteger maxConcurrentOperationCount=optionQueue.maxConcurrentOperationCount;

    // 设置/获取 name
    [optionQueue setName:@""];
    NSString *name=optionQueue.name;            

    // queue是否暂停
    BOOL isSuspended=[optionQueue isSuspended];
    // queue暂停
    [optionQueue setSuspended:true];

    // queue取消所有option
    [optionQueue cancelAllOperations];
    // 阻塞直到queue所有option完成
    [optionQueue waitUntilAllOperationsAreFinished];
option(NSOperation) 方法

    // option设置name
    [option setName:@""];
    // option 开始
    [option start];
    // option 取消
    [option cancel];

    // 阻塞直到执行完毕
    [option waitUntilFinished];

    // 获取优先级
    NSOperationQueuePriority queuePriority=option.queuePriority;
    // 设置优先级
    [option setQueuePriority:NSOperationQueuePriorityHigh];
    /*
    NSOperationQueuePriorityVeryLow = -8L,
    NSOperationQueuePriorityLow = -4L,
    NSOperationQueuePriorityNormal = 0,
    NSOperationQueuePriorityHigh = 4,
    NSOperationQueuePriorityVeryHigh = 8
    */

    // option 是否取消
    BOOL isCanceled=[option isCancelled];
    // option 是否正在执行
    BOOL isExecuting=[option isExecuting];
    // option 是否结束
    BOOL isFinished=[option isFinished];
    // option 是否异步
    BOOL isAsy=[option isAsynchronous];
    // 是否就绪
    BOOL isReady=[option isReady];

    // 获取依赖列表
    NSArray<NSOperation *> *dependencies=option.dependencies;
自定义NSOperation

#import <Foundation/Foundation.h>
@protocol YTOperationCompletionDelegate  
// 更新UI
-(void)opCompletion:(NSString *)str;    // 参数看实际情况变化
@end
@interface YTMyOperation : NSOperation
@property (nonatomic,weak) id<YTOperationCompletionDelegate> dele;
@end


#import "YTMyOperation.h"
@implementation YTMyOperation
-(void)main{
    //
    [super main];
    
    // 一些操作
    //...
    //
    dispatch_async(dispatch_get_main_queue(), ^{
        if(self.dele){
            [self.dele opCompletion:@"complete"];
        }
    });
}
@end
blockOption(NSBlockOperation : NSOperation) 方法

    // 添加
    [option addExecutionBlock:^{
    }];
InvocationOperation(NSInvocationOperation : NSOperation) 方法
3. block
block(即闭包,基于函数指针) 可用于传递数据

动画和gcd都用到:
    [UIView animateWithDuration:3 animations:^{     
    }];
    dispatch_async(dispatch_get_main_queue(),^{         
    });
  1. 声明(牢记)
@property (nonatomic,copy) void (^myBLock)(NSString *name);
  1. 方法
// 把声明中的block名字放到外面  就是类型
-(void)setMyBLock:(void (^)(NSString *))myBLock{  
}
-(void (^)(NSString *))getMyBLock{  
}
  1. 调用方法
// ^(参数类型 参名){}
[self setMyBLock:^(NSString *name) {    
    // return 10; 又返回值时+
}];
myBlock(@"name");
  1. 局部变量
// 局部变量
void (^myBlock)(NSString *name)=^(NSString *name){
};
  1. 重定义(起别名)
    typedef void (^MyBlock) (NSString *name);
    MyBlock myBlock=^(NSString *name){
    
    };
4. KVC
    KVC键值编码(k:键  V:值  C:编码)
    是一种不通过存取方法而通过属性名间接访问属性的方式。

@interface NSObject(NSKeyValueCoding)
定义了KVC相关方法
@end


用于:
    1.
    2.
使用
    PersonModel *personM=[PersonModel new];
    
    // 首先 查找set方法->若没有则查找变量->若还没有则调用setValueforUndefinedKey->若没实现setValueforUndefinedKey则蹦
    [personM setValue:@"张三丰" forKey:@"name"];
    // 首先 查找get方法->若没有则查找变量->若还没有则调用valueforUndefinedKey->若没实现valueforUndefinedKey则蹦
    NSString *name=[personM valueForKey:@"name"];


    // 多级路径
    [personM setValue:@"" forKeyPath:@"dog.name"];
    int dogAge=[personM valueForKeyPath:@"dog.age"];

PersonModel.h

#import <Foundation/Foundation.h>
@interface PersonModel : NSObject
@property (nonatomic,copy) NSString *name;
@end

PersonModel.m

#import "PersonModel.h"
@implementation PersonModel
-(instancetype)initWithDic:(NSDictionary *)dic{
    self=[super init];
    if(self){
        // 给模型所有属性赋值(等价于循环setValueForKey给属性赋值)
        [self setValuesForKeysWithDictionary:dic];
    }
    return self;
}
// 找不到键时调用
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{}

// 覆写以下方法 做额外操作
-(void)setValue:(id)value forKey:(NSString *)key{
    [super setValue:value forKey:key];
}
-(void)setValue:(id)value forKeyPath:(NSString *)keyPath{
    [super setValue:value forKeyPath:keyPath];
}
-(void)setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues{
    [super setValuesForKeysWithDictionary:keyedValues];
}
@end
5. KVO
    KVO键值观察(k:键  V:值  O:观察)
    监测某属性的变化(观察者模式的衍生)
    PersonModel *personM=[PersonModel new];
    /*
     options :会观察到并传入observeValueForKeyPath方法
        NSKeyValueObservingOptionOld     旧值
       NSKeyValueObservingOptionNew     新值
       NSKeyValueObservingOptionInitial 初始化
       NSKeyValueObservingOptionPrior   分2次调用(在值改变之前和值改变之后)
     */
    // 给personM添加观察者self,观察name属性的变化
    [personM addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    // 移除观察者self
    [personM removeObserver:self forKeyPath:@"name"];

// 观察方法(当所观察的东西发生变化时调用)
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{

    //NSKeyValueChangeNewKey  NSKeyValueChangeOldKey
    
}
6. 内存管理机制

管理原则

    OC基于引用计数管理对象的生命周期,每一个对象都绑定一个引用计数器。当通过alloc、new、copy创建对象时,引用计数为1,retain引用计数加1,release引用计数减1,当引用计数为0时则进行销毁(此时会调用delloc)   。
    基本遵循:谁创建谁释放,谁引用谁管理。

管理方式(3种)

MRC手动引用计数

    由程序员手动管理内存,当一个对象被引用时retain(如加入数组(由数组自动+1 -1),成为另一个对象的属性),当一个对象释放时release(移出数组,另一个引用该对象的对象被销毁).
ARC 自动引用计数

    由编译器通过对代码的静态分析,在适当的地方添加retain和release(如在delloc、作用范围末尾、加入数组后、set方法中)
    不能调用release retain retainCount autorelease,可以@autoreleasepool{}
    
ARC下采用非ARC编译某文件(混编):
    需在BuildPharse | Compile File找到相应文件添加 -fobjc-arc 相反+ -fno-objc-arc)


    __strong        __weak   
    __weak typeOf(self) _weakSelf=self;
    __strong typeOf(self) _strongSelf=_weakSelf;
AutoReleasePool 自动释放池  @autoreleasepool{}

    当一个对象调用autorelease时,会将该对象放入自动释放池,在自动释放池结束时向所有自动释放池中的对象发送release进行销毁.
    系统本身提供一个自动释放池,可以通过@autoreleasepool{}创建释放池.
    方法返回对象时必须autorelease
7. Category
cmd+N 选Objective-C file新建类别文件

例:
文件NSArray+YTCusArray.h
#import <Foundation/Foundation.h>
@interface NSArray (YTCusArray)
@end

文件NSArray+YTCusArray.m
#import "NSArray+YTCusArray.h"
@implementation NSArray (YTCusArray)
@end
category的作用:
    1.可以在不改变且不知道类的代码的情况下给类添加新方法。
    2.可以将类的实现分散到不同的文件或框架中便于维护.
    3.创建对私有方法的引用,实现非正式协议(即可选方法)。

    不允许添加属性(可以通过运行时库实现添加属性)
    可覆写原类中的方法。
    多个类别覆写同一方法,则在Build Phases|Compile Sources中谁在下方谁优先级大
    扩展可以添加属性,声明的方法必须实现(类别则可不实现)
8. 计时器
    三种常见的定时器:NSTimer、CADisplayLink以及GCD Timer

NSTimer

方式一:
    // 创建计时器(1s后执行)
    NSTimer * timer = [[NSTimer alloc]initWithFireDate:[NSDate distantPast] interval:1 target:self selector:@selector(myLog:) userInfo:nil repeats:YES];
    // 添加
    [[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
    /*
消息处理机制(不断循环检测事件发生)
     NSDefaultRunLoopMode   标准优先级(默认)优先级低。在滚动时NSTimer会失效,可添加到NSRunLoopCommonModes中。
     NSEventTrackingRunLoopMode 则仅在滚动时有效(用于SV和别的控件的动画)
     NSRunLoopCommonModes(二者合一)优先级高
     */
    // 激活计时器
    [timer fire];
    

// 创建并激活计时器
    NSTimer *timer2=[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:true block:^(NSTimer * _Nonnull timer) {
    }];
// 创建并激活计时器
    NSTimer *timer3=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(handleTimer) userInfo:nil repeats:true];




    // 暂停计时器
    timer.fireDate=[NSDate distantPast];
    // 继续计时器
    timer.fireDate=[NSDate date];
    // 销毁计时器
    [timer invalidate];
    timer=nil;
方式二:NSInvocation
    // 1.初始化一个Invocation对象
    //
    NSInvocation * invo = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(handleTimer:)]];
    // 或
    NSInvocation *invo=[NSInvocation new];
    [invo setTarget:self];
    [invo setSelector:@selector(handleTimer:)];
    
    // 2.创建NSTimer
    // 创建NSTimer(1s,invo,是否重复)
    NSTimer * timer = [NSTimer timerWithTimeInterval:1 invocation:invo repeats:YES];
    // 加入主循环池中
    [[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
    // 启动(开始循环)
    [timer fire];
    或
    // 创建NSTimer并启动
    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1 invocation:invo repeats:YES];
9. protocol协议
protocol协议
    只有方法声明,没有方法实现。
    遵循协议(则拥有方法的声明),就需要实现必须实现的方法(@required 修饰)。
        @protocol
        @required   // 默认
        // 必须实现的方法...
        @optional
        // 可选实现的方法...
        @end
    
10. 架构模式
常用

  MVC
  MVVM
    MVC模式    
        M   表示Model模型层,数据模型(用来存储和传递数据)  
        V    表示View视图层,界面UI(用来显示数据)
        C    表示Controller控制层,UIController(用来将数据显示到视图上,处理用户交互) 
                Model和View层不能直接通信
    MVVM模式    
        M   表示Model模型层,数据模型(用来存储和传递数据)  
        V    表示View视图层,界面UI(用来显示数据)
        VM 表示模型数据处理层,用来请求网络获取数据,并转换为UI所需的数据格式(简化C)
        C    表示Controller控制层,UIController(用来将数据显示到视图上,处理用户交互) 
上一篇 下一篇

猜你喜欢

热点阅读