面试题总结
@property与@synthesize、@dynamic
@property:声明和实现getter/setter方法,生成_成员变量
@synthesize::合成属性的getter/setter 方法
@dynamic:告诉编译器 不生成getter/setter方法 包括成员变量
@property +@sythesize //property:声明set/get方法 @sythesize 负责生成_成员变量,实现getter/setter方法。
@interface categoryController () @property (nonatomic )NSString *dynamicStr; @property (nonatomic )NSString *synthesizeStr; @end @implementation categoryController { NSString *asd; } @dynamic dynamicStr; //告诉编译器 禁止实现该属性的 getter,setter方法,同时成员变量也不会创建。 @synthesize synthesizeStr = synthesizeStr; //合成器语法 自动合成getter,setter方法,同时设置成员变量 synthesizeStr - (void)viewDidLoad { [super viewDidLoad]; //dynamic self.testStr = @"123"; NSLog(@"self.testStr==%@",self.testStr); //synthesize synthesizeStr = @"100"; NSLog(@"self.synthesizeStr==%@",self.synthesizeStr); self.synthesizeStr = @"200"; NSLog(@"synthesizeStr===%@",synthesizeStr); } - (void)setTestStr:(NSString *)testStr { asd = testStr; } - (NSString *)testStr { return asd; } @end //控制台打印 2017-06-22 11:09:11.189 TestForMe[2021:522795] self.testStr==123 2017-06-22 11:09:11.189 TestForMe[2021:522795] self.synthesizeStr==100 2017-06-22 11:09:11.189 TestForMe[2021:522795] synthesizeStr===200
二: 比较 NSString 中 copy strong区别
@property (copy ,nonatomic)NSString *cStr; @property (strong ,nonatomic)NSString *sStr; - (void)viewDidLoad { [super viewDidLoad]; [self copyWithStrongMethod1]; [self copyWithStrongMethod2]; } #pragma MARK 测试 日常 copy 和strong 的区别 - (void)copyWithStrongMethod1 { NSMutableArray *books = [@[@"book1"] mutableCopy]; Person *person = [[Person alloc] init]; person.strBooks = books; //strong属性 person.copBooks = books; //copy属性 [books addObject:@"book2"]; NSLog(@"bookArray1:%@",person.strBooks); NSLog(@"bookArray2:%@",person.copBooks); } //控制台打印 2017-07-06 15:08:30.858 TestForMe[15547:8771374] bookArray1:( book1, book2 ) 2017-07-06 15:08:30.859 TestForMe[15547:8771374] bookArray2:( book1 ) - (void)copyWithStrongMethod2 { NSMutableString *str = @"abc".mutableCopy; self.cStr = str; self.sStr = str; // str = @"asdsad".mutableCopy;不行 [str appendString:@" 123"]; NSLog(@"str1===%@ str2===%@", self.cStr, self.sStr); // str1:hello world str2:hello } //控制台打印 2017-07-06 15:08:30.859 TestForMe[15547:8771374] str1===abc str2===abc 123
备注:
备注:
使用strong,则person.bookArray1与可变数组books指向同一块内存区域,books内容改变,导致person.bookArray1的内容改变,因为两者是同一个东西;而使用copy,person.bookArray2在赋值之前,将books内容复制,创建一个新的内存区域,所以两者不是一回事,books的改变不会导致person.bookArray2的改变。
说到底,其实就是不同的修饰符,对应不同的setter方法,
1. strong对应的setter方法,是将_property先release(_property release),然后将参数retain(property retain),最后是_property = property。
2. copy对应的setter方法,是将_property先release(_property release),然后拷贝参数内容(property copy),创建一块新的内存地址,最后_property = property。
*实现原理总结
*****关于kvo:
1 监听机制,基于nsobject 两个方法willChangeValueForKey 和didChangeValueForKey,实现的。
2 当给一个属性添加观察者时候,运行时,会创建一个继承对象所属类的派生类,并且重写被观察属性的set方法,默认一个对象的isa指针会之前所属类,而这是isa会指向这个新的派生类,所以其实被观察的属性的赋值操作是在这个派生类 里实现的。
3 的当被监听的属性发生改变前,调用willChange方法 记录旧的值,改变结束 调用DidChangeValue新的值,出发kvo监听方法。
*****kvo应用场景
1 推送消息 消息时 放数组里面 我们的birgeValue显示红点提示 需要兼监听数组改变 给提示
2 视频 监听进度条
3 做轮播图监听 scrollview 监听contentOffSet
*****深拷贝 浅拷贝
1 最大的区别就是 有否创建新对象。深拷贝内容拷贝,浅拷贝指针拷贝(内存地址拷贝)
2 深拷贝,修改一个对象不影响另一个对象。
3 浅拷贝,修改一个对象影响另外一个对象
大体上 copy mutable copy 策略是深拷贝
retain strong是浅拷贝
*****SDWebImage细节
1 sd_setImageWithURL
2 SDWebImageManager 单例 downloadImageWithURL
内部 SDImageCache类(nscache)以以url为key queryDiskCacheForKey方法 Memory Cache 以url为key去内存中查询缓存图片,如果没有 Disk Cache:去磁盘上找。
如果磁盘找到,会将图片设置到memory cache中。
3 如果缓存数据查询成功,则返回,不成功则请求网络self.imageDownloader down…
4 如果下载成功 [self.imageCache storeImage]储存 completedBlock回调前端展示
ps 磁盘缓存清除策略
1 清理过期缓存
2 清理写入时间早的图片
@interface SDImageCache : NSObject
@property (assign, nonatomic) NSInteger maxCacheAge;//最大缓存时间
@property (assign, nonatomic) NSUInteger maxCacheSize;//最大缓存空间
//设置最大缓存空间
[SDImageCache sharedImageCache].maxCacheSize = 1024 * 1024 * 50; // 50M
SDWebImage Bug
磁盘图片渲染之前,需要得到图片的原始像素数据,然后去做绘制操作,所以图片需要解压缩。
*****公司刷新 流程
size :取多少
offset:从哪里取
count:总数
刷新:
设定size 20条 10条,offset 为0 加到数组中
加载:
设定size20条 10条,第一次 获取数据数组长度 offset 从这取值 取size条,加到数组。
判断更多 has 数据数组个数< count总数
设置footer view 给个提示 没有更多
***** svpullrefresh 原理
创建个scrollView的分类 分类添加属性刷新头部显示的view 高度60 添加头部刷新view为scrollview的观察者,监听contentOffSet的改变,刷新头部view 有几种状态,加载状态,初始状态,停止状态,拖拽状态,在观察者监听方法里面,根据几种状态切换执行layoutSubview的显示
*****bug
当下拉刷新比较少时候 会先调用下拉加载 在调用下拉刷新,由于头部view,后尾部view都是scrollview的观察者,所以当offset改变时候,观察者方法都会调用,然后判断的也都是拖拽,
解决:尾部控件拖拽状态进入加载还不都,还要&&上scollview.cotentset>0
uiscrollview的分类
/**********************************************************************************/
*****tableview 滑动 cell 崩溃 (会议人气榜)
且仅仅4s崩溃,其他的不崩溃 而且会有内存明显的飙升 正常100左右飙升到800
断点调试 崩溃在sdwebimage里面 沙盒取出的图片转码 转位图时候,正常我们设置图片imageview setimage 都是在主线程中设置的 这其就包括解压图片为位图(很耗cpu) 然后calyer在view上做渲染。sdwebimage做法是开子线程去去做这个位图的解压缩,然后缓存 供ui使用,去沙盒中去图片的时候不做任何处理,直接取,这次奔溃的原因就是后台返回的图片太大 3000*5000,方案有两个第一大图片不处理 不解码这样性能差点 但不崩溃
第二种是 沙盒取出的图片 先等比压缩下。
我的方案是综合下 沙盒取出图片先判断如果款大于屏幕宽度 等比压缩下,小的不压缩,然后再去转码
*******多线程场景应用
qq分享要求的图片1m以内,后台传的图片1.2m发布出去 回调不掉。
方案:下载图片nsdata datawithurl 网速慢直接卡死 要开线程 图片存储沙盒,等比压缩图片
xmpp 环境配置
材料:openfire服务器 mysql数据库(默认装到控制面板)
1 openfire mac版 基于java开发的 所以要求电脑有java运行环境
没有的话需要安装jdk 查看java运行环境 终端执行命令 运行java -version
2 mysql (服务端的数据库)使用是需要有账户密码默认装到控制面板)
1》安装完 mysql 默认账户是root 密码为空
2》终端命令配置命令行配置 开启mysql 并设置密码
3》创建的数据库默认四个文件 有个test文件
4》管理工具navcat 还有个海豚(mysqlworkbeech)的 登录输入连接名称(自定义)输入IP地址 端口号默认3306
账户名称 root 密码(你配置过得)配置的数据库名称为你自定义的名称
3 关联openfire 和数据库1 导入openfire数据表文件到mysel(创建字段包括用户等)
1》openfire建立数据库文件openfire数据库编码选择utf-8的
2》默认open fire数据库安装到/user/local/openfire/ 数据库脚本保存在/user/local/openfire/ /resources/database/中
支持很多种数据库 保存mysql的数据库到桌面 导入到mysql中,这样mysql就添加好数据库字段了
4 关联openfire 和数据库1 后台管理设置关联数据库mysql
后台配置 选中驱动类型:mysql 指定mysql路径 输入mysql 用户名密码:root 密码:123456
配置openfire 后台账户密码 admin 123456
设置jid:
***** coast / 宏定义
coast(常量):修饰变量之用 (可以修饰基本数据类型 int ,oc对象:nesting),标记变量只读…
应用场景:1 修饰全局变量 2 修饰方法参数
PS:NSString *coast str;// 当用在全局变量,防止外部引用extern 修改..
-(void)setTest:(int coast)a { } 修饰方法参数,防止参数被修改,修改了,当然set方法你就外面白白设置了!~
ps:什么叫做常量,10.@“SDSADD” 叫常量 nssting *a a叫做变量....
***** static / extern 全局变量 局部变量牛逼闪闪
static:修饰变量(全局,局部)使用
修饰局部变量:
作用:延长局部变量生命周期 (类似给局部变量变为全局变量的意思!)
ps:局部变量本身存储堆栈区,方法结束局部变量随之销毁;static修饰后将局部变量copy到静态区,修饰后变量在运行中在静态区给局部变量分配一次内存空间,且仅仅执行一次,程序运行期间变量一直存在不会销毁。
ps:打点断 ,发现下次执行这里断点过到下面去了。
修饰全局变量:
主要是作用域的问题,static修饰后仅在本类中可以使用,无法extain引用,全局变量则可以外部引用。
场景:int做自增运算
extern:外部引用 UIKIT EXTERN(牛逼闪闪的宏定义 吼吼~~)
一个类中声明(及时写在方法里面也无妨),另一个类extern 可以直接引用。
ps:无需等到程序会否执行到该方法,程序启动即分配内存空间,所以无需加载到该方法。
ps:个人理解,类似通过extern关键字从静态区 引出一个全局变量的意思,然后重新声明,使用。。。
全局变量:变量存储在静态区,程序运行时分配一次内存空间,然后不会再去执行了。
局部变量:存放在栈空间中,方法执行结束,变量销毁。
????为什么 类方法 要用static 修饰全局变量
***** 项目性能优化
1 懒加载 场景:初始化UI控件 2NSDateFormatter(日期格式化)
2 tableview优化 实现: 高度,数据 提前缓存,tableview只做赋值运算 减少subVies数量,rowHeight sectionHooterHeight 直接设定,少用代理
3 常识注意
***** NSURLCache
缓存原理 NSURLQequest 对应一个NSURLURLCacheResponse
缓存NSURLCache *cache = [NSURLCache shareURLCache];//掌握全局缓存
***** Block常识 (一)
方法常用声明:@property (copy) void(^MyBlock)(void); 如果超出当前作用域之后仍然继续使用block,那么最好使用copy关键字,拷贝到堆区,防止栈区变量销毁
_weak typeof(self) weakSelf = self;
因此,__block和__weak修饰符的区别其实是挺明显的:
1.__block不管是ARC还是MRC模式下都可以使用,可以修饰对象,还可以修饰基本数据类型。
2.__weak只能在ARC模式下使用,也只能修饰对象(NSString),不能修饰基本数据类型(int)。
3.__block对象可以在block中被重新赋值,__weak不可以。
PS:__unsafe_unretained修饰符可以被视为iOS SDK 4.3以前版本的__weak的替代品,不过不会被自动置空为nil。所以尽可能不要使用这个修饰符。
***** Block和copy (二)
为什么要用copy:出于作用域考虑,默认block 存放在栈中,函数调用,栈分配内存,函数结束释放内存,block 销毁。再次调用block 时候报错野指针错误。当前block 变量指向的被释放的内存地址。所以需要copy到堆中,包住block的命。
“他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。”
***** Block copy/strong (三)
使用retain也可以,但是block的retain行为默认是用copy的行为实现的,
因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。
***** Block copy/strong 扩展
block内部不引入外部变量:__ NSGlobalBlock
block内部引入外部变量 :__ NSStackBlock
***** weak 实现原理
runtime维护这个一个weak表(哈希表),记录已对象的地址为key,value为 所有指向该对象的weak弱指针地址的数组,当对象销毁时候通过weak表中该对象地址的value,查找到存有所有弱指针的地址的数组,赋值为nil,然后从weak表中删除。
对象销毁 会调用objec_clear_deallocating函数
assign weak 区别
assign:修饰对象,和基本数据类型;当被修饰的变量指向变量释放或置空,会出现野指针错误!
weak:只能修饰对象,不会出现野指针错误,当被修饰的变量指向的变量释放或是置空,被修饰变量指向nil,不会出现野指针错误。
引申
***** 内存分析
静态内存分析 analyze、分析/ 蓝色
例如:逻辑错误
logic error / Dead store/Memory
不是太准 不可变赋值给可变数组 ,调方法时候传入的字典参数未实例化
动态内存分析 profile -allocation /leaks 侧面/分配/泄漏
*****手势 响应者链条
分两块,
1 定位接收者
2 响应者链条
1定位接收者 当点击屏幕的ui出发一个事件,流程是事件添加到UIAplication的事件组,传递事件经历 window ,父控件且判断控件是否接受事件,如果是,则父控件遍历子控件,判断当前出发点是否在子控件上,继续遍历直到找到触发该点的最后一个子控件,事件传递不可以断,以为这所有控件务必可以处理事件,获取执行触发事件的控件。
ps:这就说明了 为什么交互期间中间有个什么uiimageview等不能交互的夫控件,导致子控件不接受响应事件
可以接受响应事件的控件需要继承uiresponder 但还不够 需要可以交互 不是隐藏的 alpha值不是太小
2 响应者链条,功能是一个事件的发生,可以被多个控件获取。回传靠的是super执行方法
举例子:view上事件触发 默认事件互传给父控件,继续回传父控件,控制器.view 控制器(一样继承uiresponder);如果控制器还有父控制器那就父控件传递 给控制器 然后self.view 然后父控制器 window uiapplication
*****注册登录 加密流程 对称非对称加密
*****get post tcp udp
*****缓存策略
*****镂空的遮罩
0 思路:蒙版.layer.mask = layer对象
1 创建蒙版
2 绘制贝塞尔路径 添加反转图形(叠加部分会镂空)
3 创建layer(CAShapeLayer子类).path = 贝塞尔路径.path
4 设置 蒙版.layer.mask = layer对象
*****ios webp格式图片应用 及交互
博客园详解
***** ios 堆栈详解
博客园详解