2020-07-24

锁 OSSpinLock 自旋锁 实现机制:忙等 操作重点:原子操作
1.自旋锁
2.互斥锁
3.读写锁
4.信号量
5.条件锁
6.递归锁
需导入头文件:

import <libkern/OSAtomic.h>

pragma mark --加锁

-(void)addLock{
__block OSSpinLock oslock = OS_SPINLOCK_INIT;
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"准备上锁");
OSSpinLockLock(&oslock);
NSLog(@"已经上锁");
OSSpinLockUnlock(&oslock);
NSLog(@"解锁成功");
});
}
锁 OSSpinLock 自旋锁 实现机制:忙等 操作重点:原子操作 https://www.jianshu.com/p/c8ed92cc43b6

iOS哪些操作会造成内存泄漏
1.Block循环引用(比如mj的下啦刷新需要用weakself)cmp.refreshingBlock = refreshingBlock;这一句,这里的refreshingBlock是属于MJRefreshHeader的强引用属性
2.delegate循环引用问题
3.NSTimer循环引用
4.非OC对象内存处理
比如常用的滤镜操作调节图片亮度 CGImageRelease(ref);//非OC对象需要手动内存释放
5.地图类处理
使用完毕时将地图、代理等滞空为nil,注意地图中标注(大头针)的复用,并且在使用完毕时清空标注数组等。
6.大次数循环内存暴涨问题
该循环内产生大量的临时对象,直至当前runloop休眠前才释放掉,可能导致内存泄漏,解决方法为在循环中创建自己的autoReleasePool,及时释放占用内存大的临时变量,减少内存占用峰值。

通过调用autorelease方法把释放对象的任务交给Autoreleasepool对象,当Autoreleasepool对象执行到[pool drain]方法的时候会对自动释放池中所有的对象执行一次release操作,然后+ (instancetype)student方法中创建的对象引用计数就会被-1了,如果引用计数变为0了,对象自然就释放了
调用方获取对象以后自己retain持有一下对象,防止使用期间对象被释放了,用完release释放一下
for (int i = 0; i < 100000; i++) {

    @autoreleasepool {
        
        NSString *string = @"Abc";
        
        string = [string lowercaseString];
        
        string = [string stringByAppendingString:@"xyz"];
        
        NSLog(@"%@", string);
        
    }
    
}

wk的js交互
self.methodArray = [[NSArray alloc]initWithObjects:XCJSGoToHousingDetails,XCJSVrviewer,nil];

 WKWebView *wkWebView = [self.curVC.view viewWithTag:WEBVIEW_TAG];

for (int i = 0; i < self.methodArray.count; i++) {
    
    [wkWebView.configuration.userContentController addScriptMessageHandler:[[weakScriptMessageDelegate alloc] initWithDelegate:self.curVC] name:self.methodArray[i]];
}

//WKScriptMessageHandler协议方法

  • (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    //code

    NSLog(@"%@",NSStringFromSelector(_cmd));
    [self.wkJSSDK setWKScriptMessage:message];
    }
    cookie都存在哪里 多个wkwebview的cookie怎么同步的
    怎么样保护一个线程安全
    内存管理机制(例如一个列表 一直滑动什么时候会崩溃 给app的最大内存分配是虚拟内存还是实际内存)
    设计模式 单例模式 代理模式 Cocoa模式等等
    其中包括常见的软件设计原则,责任链、适配器、桥接、命令、单例、策略模式等等,不要告诉我你只是看了几本书,面试官会让你结合实际业务场景,现场考察你对设计模式的运用和理解的。

组件化

1.runtime https://www.jianshu.com/p/c3a5ffcd856b
runtime
1.消息传递
首先通过对象的isa指针找到对应的class(对象都是结构体里面包含isa指针,成员变量等)
然后在class的methodlist中找对应的方法
如果class中找不到,就继续往它的superclass中找
一旦找到这个函数,就去执行它的实现IMP
如果找不到先进入+(BOOL)resolveInstanceMethod:(SEL)sel
方法 可以
+(BOOL)resolveInstanceMethod:(SEL)sel
{
// 以"@@:"作为方法签名类型返回。这里第一字符@代表函数返回类型NSString,第二个字符@代表self的类型id,第三个字符:代表_cmd的类型SEL。

    if (sel == @selector(foo:)) {
        class_addMethod([self class], sel, (IMP)fooMethod, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];

}
void fooMethod(id obj,SEL _cmd){
NSLog(@"fooMethod");
}
如果这个方法没有实现替代返回yes继续
备用接收者
-(id)forwardingTargetForSelector:(SEL)aSelector
-(id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector==@selector(foo)) {
return [Person new];
}
return [super forwardingTargetForSelector:aSelector];
}
这个方法返回nil的话
进入-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}

-(void)forwardInvocation:(NSInvocation *)anInvocation
{
SEL sel = anInvocation.selector;
// Person *p = [Person new];
Person *p = [[Person alloc] init];

if ([p respondsToSelector:sel]) {
    [anInvocation invokeWithTarget:p];
}
else{
    [self doesNotRecognizeSelector:sel];
}

}

如果再没有实现的话就报错了

关联对象(Objective-C Associated Objects)给分类增加属性
分类不能添加属性主要是因为不能实现set和get方法

import <objc/runtime.h>

static char kDefaultColorKey;
//set方法
-(void)setDefaultColor:(UIColor *)defaultColor
{
objc_setAssociatedObject(self, &kDefaultColorKey, defaultColor, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
//get方法
-(UIColor *)defaultColor
{
return objc_getAssociatedObject(self, &kDefaultColorKey);
}

方法魔法(Method Swizzling)方法添加和替换和KVO实现
方法添加
class_addMethod([self class], sel, (IMP)fooMethod, "v@:")
方法替换
+(void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL oldSel = @selector(viewDidLoad);
SEL newSel = @selector(viewDidLoadNew);
Method oldM = class_getInstanceMethod(class, oldSel);
Method newM = class_getInstanceMethod(class, newSel);
// 判断newM方法是否存在
BOOL didAddmethod = class_addMethod(class, oldSel, method_getImplementation(newM), method_getTypeEncoding(newM));
if (didAddmethod) {
class_replaceMethod(class, newSel, method_getImplementation(oldM), method_getTypeEncoding(oldM));
}else{
method_exchangeImplementations(oldM, newM);
}
});
}
注意点方法需要在load里面执行 单例只执行一次

  • load 作为 Objective-C 中的一个方法,与其它方法有很大的不同。它只是一个在整个文件被加载到运行时,在 main 函数调用之前被 ObjC 运行时调用的钩子方法。其中关键字有这么几个:

文件刚加载
main 函数之前
钩子方法
实现NSCoding的自动归档和自动解档
原理描述:用runtime提供的函数遍历Model自身所有属性,并对属性进行encode和decode操作。
核心方法:在Model的基类中重写方法:

import <objc/runtime.h>

  • (id)initWithCoder:(NSCoder *)aDecoder
    {
    if (self = [super init])
    {
    unsigned int outCount;
    Ivar *ivars = class_copyIvarList([self class], &outCount);
    for (int i = 0; i < outCount; i ++)
    {
    Ivar ivar = ivars[i];
    NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
    [self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
    }
    }
    return self;
    }

  • (void)encodeWithCoder:(NSCoder *)aCoder
    {
    unsigned int outCount;
    Ivar *ivars = class_copyIvarList([self class], &outCount);
    for (int i = 0; i < outCount; i ++)
    {
    Ivar ivar = ivars[i];
    NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];
    [aCoder encodeObject:[self valueForKey:key] forKey:key];
    }
    }
    // 自动归档/解档
    NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"PersonInfo"];
    if (data) {
    // 解档使用
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    NSLog(@"name: %@", person.name);
    } else {
    Person *person = [Person new];
    person.name = @"devZhang";
    person.age = @(35);
    person.company = @"ShengXue";
    person.job = @"iOSDev";
    person.address = @"龙岗坂田国际中心";
    // 归档存储
    data = [NSKeyedArchiver archivedDataWithRootObject:person];
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"PersonInfo"];
    }
    实现字典和模型的自动转换(MJExtension)
    原理描述:用runtime提供的函数遍历Model自身所有属性,如果属性在json中有对应的值,则将其赋值。
    核心方法:在NSObject的分类中添加方法

  • (instancetype)initWithDict:(NSDictionary *)dict {

    if (self = [self init]) {
    //(1)获取类的属性及属性对应的类型
    NSMutableArray * keys = [NSMutableArray array];
    NSMutableArray * attributes = [NSMutableArray array];
    /*
    * 例子
    * name = value3 attribute = T@"NSString",C,N,V_value3
    * name = value4 attribute = T^i,N,V_value4
    */
    unsigned int outCount;
    objc_property_t * properties = class_copyPropertyList([self class], &outCount);
    for (int i = 0; i < outCount; i ++) {
    objc_property_t property = properties[i];
    //通过property_getName函数获得属性的名字
    NSString * propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
    [keys addObject:propertyName];
    //通过property_getAttributes函数可以获得属性的名字和@encode编码
    NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
    [attributes addObject:propertyAttribute];
    }
    //立即释放properties指向的内存
    free(properties);

      //(2)根据类型给属性赋值
      for (NSString * key in keys) {
          if ([dict valueForKey:key] == nil) continue;
          [self setValue:[dict valueForKey:key] forKey:key];
      }
    

    }
    return self;

}

2.kvc/kvo
kvo机制
kvo的作用主要是观察某个对象的属性变化
kvo的实现原理 通过runtime 在观察某个对象的时候,kvo动态创建了一个当前类的子类,并且为这个新的子类重写了观察属性的setter方法
重写的setter方法会负责在调用原setter方法前后,通知所有观察对象属性值的更改情况
kvo
1.iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么)
利用runtimeAPI动态生成一个子类,并且让instance对象的isa指向这个全新的子类
当修改instance对象的属性时,会调用Foundation的NSSetXXXValveAndNotify函数
willChangeValueForkey
父类原来的setter
didChangeValueForKey
内部会触发监听器(obserer)的监听方法(observeValueForKeyPath:ofObject:change:context)
2.如何手动触发KVO?
手动调用willChangeValueForkey和didChangeValueForKey
3.直接修改成员变量会触发KVO吗?
不会触发KVO,因为只有触发set方法才会触发(
变量=不会触发 .变量=才会触发)
kvc
1.基本概念
可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态地访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。
2.赋值方法

  • (nullable id)valueForKey:(NSString *)key;

  • (void)setValue:(nullable id)value forKey:(NSString *)key;

  • (nullable id)valueForKeyPath:(NSString *)keyPath;

  • (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

3.赋值原理

找到对应的key,然后将一个已经准备好的值赋过去
方法- (nullable id)valueForKey:(NSString *)key;
内部流程
1.程序优先调用set<Key>:属性值方法,代码通过setter方法完成设置。注意,这里的<key>是指成员变量名,首字母大小写要符合KVC的命名规则
2.如果没有找到setName:方法,KVC机制会检查+ (BOOL)accessInstanceVariablesDirectly方法有没有返回YES,默认该方法会返回YES,如果你重写了该方法让其返回NO的话,那么在这一步KVC会执行setValue:forUndefinedKey:方法,不过一般开发者不会这么做。所以KVC机制会搜索该类里面有没有名为<key>的成员变量,无论该变量是在类接口处定义,还是在类实现处定义,也无论用了什么样的访问修饰符,只在存在以<key>命名的变量,KVC都可以对该成员变量赋值。
3.如果该类即没有set<key>:方法,也没有_<key>成员变量,KVC机制会搜索is<Key>的成员变量。
4.和上面一样,如果该类即没有set<Key>:方法,也没有
<key>和_is<Key>成员变量,KVC机制再会继续搜索<key>和is<Key>的成员变量。再给它们赋值。
5.如果上面列出的方法或者成员变量都不存在,系统将会执行该对象的setValue:forUndefinedKey:方法,默认是抛出异常。
6.特别需要注意的是:如果开发者想让这个类禁用KVC里,那么重写+ (BOOL)accessInstanceVariablesDirectly方法让其返回NO即可,这样的话如果KVC没有找到set<Key>:属性名时,会直接用setValue:forUndefinedKey:方法。
https://www.jianshu.com/p/5273c8e29799

https://www.jianshu.com/p/c3a5ffcd856b/https://www.jianshu.com/p/c3a5ffcd856b
3.线程/线程锁 原子安全
4.gcd
用过哪些api
5.内存管理
哪些方法和操作会导致内存泄露
6.崩溃异常怎么修复
7.@synthesize 和 @dynamic分别有什么作用
@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法
@dynamic告诉编译器:属性的setter与getter方法由用户自己实现,不自动生成(当然对于readonly的属性只需提供getter即可)
为什么block要使用copy而不是strong或者其他属性修饰?
block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈上的,而不是在堆上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。因为栈区的特点就是创建的对象随时可能被销毁,一旦被销毁后续再次调用空对象就可能会造成程序崩溃,在对block进行copy后,block存放在堆区.
使用retain也可以,但是block的retain行为默认是用copy的行为实现的,
因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。

category的加载处理过程
1.通过Runtime加载某个类的所有Category数据
2.把所有Category的方法,属性,协议数据,合并到一个大数组中,后面参与编译的Category数据,会在数组的前面
3.将合并后的分类数据(方法,属性,协议)插入到类原来数据的前面

+load方法会在runtime加载类,分类时调用 在mian函数之前调用
每个类,分类的+load,在程序运行过程中只调用一次

调用顺序
1.先调用类的+load
按照编译先后顺序调用(先编译,先调用)
调用子类的+load之前会先调用父类的+load

2.再调用分类的+load
按照编译先后顺序调用(先编译,先调用)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345