-
iOS下常用类库整理
- 网络处理 AFNetWorking Alamofire
- 数据库 fmdb sqlite.swift
- 图片异步加载 sdwebimage kingfisher
- 分享 ShareSDK
- 菊花君 MBProgressHUD SVProgressHUD
- 轮播 SDCycleScrollView 自己封装吧
- json解析 MJEXension SwiftJson
- 视频 IJKMediaplayer
- 推送 极光
总结学习学习Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法
-
- 消息与函数调用 区别
oc 中消息型语言与函数调用 oc其运行的代码由运行环境决定 函数调用 由编译器决定
举例说明多态情况下: oc 运行时不管是否多态在运行时去查找这个方法
函数 是多态的话会运行时按照虚方法表来查到底要执行的方法
明白oc中所有的对象分配是在堆上的,不是在栈上的,延用c 语言的方式
NSString astackstring 错误 而只能这样使用NSString *str; 去手动分配
- 消息与函数调用 区别
2.内存上面的问题
分配在堆上的对象等需要手动管理 栈上的会在弹出时自动清理 如基本类型的变量 包括一系列CG开头的
oc中将内存管理抽象出来,不需要用malloc 和 free 分配释放 而去使用引用计数的方式来管理3.头文件中尽量少引用其他头文件,说不定就会造成头文件引用
@class 来标明其它类属性 优雅解决
使用协议呢 将其放在单独的文件更好4.多用类型常量少用预处理
a.h中预定义 了个 #define Max 8 那么有b.h 引入这个a.h会把 所有Max 都会换成这个的
且预处理的不含类型信息(缺点)使用 static const double max = 8 这种方式会更合适点
使用const标记的 , 想要对它修改 编译就会让它报错
如果不加static ,编译器会为其创建一个外部符号 如果另一个类中也声明了这样的常量 max 编译器会给出错误提示
用static这个可以来标记这种变量命名一样是否可以在多个类中使用
加了 就不会给他创建一个外部符号,来表示 这个常量就是在本类使用的
static const 修饰的只会在编译单元内 私有这样来说比较通俗(什么时编译单元内呢, 实际就是.m文件的东西都属于编译单元)
定义这些常量的位置讲究, 是否公开这个常量 不公开 放在实现文件 这样做会更好
命名规范加类名前缀来避免空间 上的重名冲突
如通知的典范,通知名字字符的定义
.h 中 extern NSString *const eocstring;
.m NSString *const eocstring = @“窗口变化饿了”
怎么看常量定义: 从右向左解读
eocstring 常量 什么样的常量 是一个指针, 这个指针指向nsstring
extern 关键标识的常量 会放在 全局符号表中
只能定义一次,在实现文件定义好了过后 编译器会在数据段为这个字符串分配存储空间
这种方式会让编译器来确保常量值不变 ,且不管在哪个类中定义的这个 所有地方都可以用
- 5.用枚举的时机 : 状态、选项、状态码
ECsucceed = 1,
ECerror,
};
//某种状态可以组合 的方式比如在使用到 animation 选项的时候多种状态组合实现
enum ECtype:NSInteger{
ECnone = 0 ,
ECsucceed = 1<<0, //00000001
ECperfect= 1<<1, //00000010 00000011 3
};
typedef enum ECtype ectype;
ectype atype = ECsucceed | ECperfect ;
//这种不能判断用与ecnone为0这种 与符号为0嘛
if ((atype & ECsucceed ) && (atype & ECperfect) ){
NSLog(@"开启完美 成功模式");
}
- 6.关于runtime机制的理解
先说原理不好理解,因此先说说它能干什么- 如果是在程序运行过程中 , 希望动态创建一个类(比如kvo底层就是基于这个特 性)
- 程序运行过程中希望动态的生成一些属性或者方法 包括修改
- 遍历一个类的所有成员变量和方法 ,如一个类的属性方法特别多的时候
//这个东西 可以用于深层次开发框架
如:在归档的时候
unsigned int count = 0;
Ivar ivars = class_copyIvarList([PYPerson class], &count);
for (int i = 0; i
- 常用函数
objc_msgSend : 给对象发送消息
class_copyMethodList : 遍历某个类所有的方法
class_copyIvarList : 遍历某个类所有的成员变量
class_..... 这是我们学习runtime必须知道的函数! - 关于深入理解下runtime的总结
- 1.objc_msgSend它具体是如何发送消息:
1.首先根据receiver对象的isa指针获取它对应的class;如person 这样的类实质被转成类似这样的结构
struct objc_class {
Class isa ;
};
2.优先在class的cache查找message方法,如果找不到,再到methodLists查找;
//objc_class 的父类是这样的
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; //Cache其实就是一个存储Method的链表
......
}
3.如果没有在class找到,再到super_class查找;
4.一旦找到message这个方法,就执行它实现的IMP。(指向函数的指针)
//我们看到的selector 以及函数等method里面实质被ocruntime转成一个结构体大概是这样的
struct objc_method {
SEL method_name
char *method_types
IMP method_imp
}
综上所述过程是这样当对象receiver调用方法message时,首先根据对象receiver的isa指针查找到它对应的类,然后在类的methodLists中搜索方法,如果没有找到,就使用super_class指针到父类中的methodLists查找,一旦找到就调用方法。如果没有找到,有可能消息转发,也可能忽略它。但这样查找方式效率太低,因为往往一个类大概只有20%的方法经常被调用,占总调用次数的80%。所以使用Cache来缓存经常调用的方法,当调用方法时,优先在Cache查找,如果没有找到,再到methodLists查找。
7. oc运行特性的简单运用,即简单函数式编程与响应式编程的实现
@interface Person : NSObject
//1. 传统方式
//- (void)run;
//- (void)study;
//-(void)sleep;
//2.稍微像原始oc的方式
//-(Person*)run;
//-(Person*)study;
//3.最终形态
@property(nonatomic,strong) NSString *name;
-(Person* (^) ())runblock;
-(Person* (^) (NSString*studytime))studyblock;
-(Person* (^) (NSString *sleeptime))sleepblock;
+(void )adetails;
@implementation Person
{
NSInteger age;
NSString *pcode;
}
//-(void)run{
// NSLog(@"i run over");
//}
//
//-(void)study
//{
// NSLog(@"i study over");
//}
//-(void)sleep
//{
// NSLog(@"i go sleep");
//}
//-(Person *)run
//{
// NSLog(@"i run over");
// return [[Person alloc]init];
//}
//-(Person *)study{
// NSLog(@"i study over");
// return [[Person alloc]init];
//}
-(Person *(^)())runblock{
Person* (^block)() = ^() {
NSLog(@"我跑完步了");
return self;
};
return block;
}
-(Person *(^)(NSString*studytime))studyblock{
Person* (^block)(NSString*studytime) = ^(NSString*studytime) {
NSLog(@"我学习了%@小时,终于学完了",studytime);
return self;
};
return block;
}
-(Person *(^)(NSString * sleeptime))sleepblock
{
Person * (^block)(NSString *sleeptime) = ^ (NSString *sleeptime)
{
NSLog(@"我在%@,准时入睡",sleeptime);
return self;
};
return block;
}
+(void)adetails
{
//这里我们获取函数名字
id classobj = objc_getClass([@"Person" UTF8String]);
//存储属性的property 属性的个数
unsigned int count = 0 ;
//成员变量的个数
unsigned int icount = 0 ;
class_copyPropertyList(classobj, &count);
class_copyIvarList(classobj, &icount);
// objc_property_t *properties = class_copyPropertyList(classobj, &count);
// Ivar *ivars = class_copyIvarList(classobj, &icount);
//打印属性
NSLog(@"属性%d,成员变量%d",count,icount);
}
-(NSString *)description{
return @"本身的person描述";
}
-(NSString*) currentdescription
{
return @"你没有权限来查看我";
}
-(instancetype)init{
self = [super init];
Method orgdescription = class_getInstanceMethod([Person class], @selector(description));
Method currentdecription = class_getInstanceMethod([Person class], @selector(currentdescription));
method_exchangeImplementations(orgdescription, currentdecription);
//实现拦截重写description方法的描述 会打印你没有权限查看我
return self ;
}
//调用 //这种方式就叫传统的函数式编程
Person * p = [[Person alloc]init];
//第三方自动布局的思想就是响应式的 .sd_layout().left(90).right(80)
//模仿实现的最终目标 p.studyblock().runblock().sleepblock()
//1. 先实现这种调用 [[p run]study];
// [[p run] study];
//2. 思考 上面这种实际肯定就是block方式调用的
p.studyblock(@"8").runblock().sleepblock(@"10");
[Person adetails];
//这样 就让外部
NSLog(@"%@",p);
tips :
一个oc类的+load方法是在app开始运行时首先会被调用执行的方法,也就是说.
当app被点击,再被系统加载app程序进入内存后,首先会实例化
所有类到代码或全局区,就会调用类的load方法,如果要给一个类做方法交换,则一般情况
放在load方法中来操 作。方法交换一旦完成,则程序运行中全局生效。
-
各种实用性总结
oc属性关键词场景:readwrite,readonly,assign,retain,copy,nonatomic 、atomic、strong、weak属性的作用?
readWrite读写特性, 可读可写.
readonly只读, 只有getter, 没有setter.
assign一般用于基本数据类型和ID类型.
copy拷贝, 一般用于 NSString. 分为深拷贝和浅拷贝, 深拷贝拷贝的是对象, 浅拷贝拷贝的是指针.
nonatomic非原子性, 不考虑线程安全, 优点是效率高.
atomic原子性, 优点是线程安全, 缺点是效率低.
strong强引用, 和MRC下的retain一样. weak弱引用, 类似MRC下的assign. 但是要注意的是strong和weak都是修饰对象类型的属性的, 不能修饰基本数据类型. ARC下仍然使用assign修饰基本数据类型.
- 关于如何优化表视图的考虑
表视图在开发中是最常用的控件,但关键在于利用好cell的重用与绘制方式
少用圆角(貌似采用重写画图片的方式会效率点) ,减少动画,cell中的计算缓存高度,避免阻塞主线程比如一些复杂的计算或者网络图片转换格式然后切换主线程显示等操作,透明度上的操作,富文本考虑是否需要完全需要的情况建议用yykit那套,不然很多需要自己做缓存,如事先计算各个内容的布局高度存下,少用xib而采用storyboard的方式.实在需要大量优化的话个人觉得只有找异步绘制的方案了.texture 应该能搞定大部分优化.
-
OC单例
+ (ZMYSingleton *) sharedInstance{
static LOSingleton *sharedInstance = nil ;
static dispatch_once_t onceToken; //线程锁
dispatch_once (& onceToken, ^ {
// 最多调用一次
sharedInstance = [[ZMYSingleton alloc] init];
});
return sharedInstance;
}
- 文件沙盒
沙盒有3个文件夹:Documents, Library 和 tmp。
Documents:保存程序中建立的或在程序中浏览到的文件数据
iTunes备份和恢复的时候会包括此目录
Library/Caches:存放缓存文件,iTunes不会备份此目录,目录下文件在应用退出时不删除
tmp:提供一个即时创建临时文件的地方。
iTunes在与iPhone同步时,备份所有的Documents和Library文件。
iPhone在重启时,会丢弃所有的tmp文件。
iOS进阶https://www.jianshu.com/p/c47c24ab1e76/
//kvc kvo 记录
KVC的底层实现?
当一个对象调用setValue方法时,方法内部会做以下操作:
- 检查是否存在相应key的set方法,如果存在,就调用set方法
- 如果set方法不存在,就会查找与key相同名称并且带下划线的成员属性,如果有,则直接给成员属性赋值
- 如果没有找到_key,就会查找相同名称的属性key,如果有就直接赋值
- 如果还没找到,则调用valueForUndefinedKey:和setValue:forUndefinedKey:方法。
- 这些方法的默认实现都是抛出异常,我们可以根据需要重写它们。
- kvo基于runtime机制实现。
- 使用了isa 混写(isa-swizzling),当一个对象(假设是person对象,person的类是MYPerson)的属性值(假设person的age)发生改变时,系统会自动生成一个类,继承自MYPerson :NSKVONotifying_MYPerson,在这个类的setAge方法里面,调用[super setAge:age] [self willChangeValueForKey:@"age"] 和 [self didChangeValueForKey:@"age"]
,而这两个方法内部会主动调用监听者内部的 - (void)observeValueForKeyPath 这个方法。 - 想要看到NSKVONotifying_MYPerson很简单,在self.person.age = 20; 这里打断点,在调试区域就能看到 _person->NSObject->isa=(Class)NSKVONotifying_MYPerson.同时我们在 self.person = [[MYPerson alloc]init];后面打断点,看到_person->NSObject->isa=(Class)MYPerson,由此可见,在添加监听者之后,person类型已经由MYPerson被改变成NSKVONotifying_MYPerson
缺点就是编译器不会检查字符串的写错
- nil Nil NULL NSNull
nil:指向oc中对象的空指针
Nil:指向oc中类的空指针 //类没找到
NULL:指向其他类型的空指针,如一个c类型的内存指针
NSNull:在集合对象中,表示空值的对象 字典好像可以填这个不能填nil