iOS基础
字节/字符
int
int的取值范围
32位和64位
int = 4byte = 4*8bit = 32bit
-2^(32-1) ~ 2^(32-1)-1
-2147483648-2147483647
16位
int = 2byte = 2*8bit = 16bit
-2^(16-1) ~ 2^(16-1)-1
计算
load
load方法:对于运行期系统的每个类(class)及分类(category),都必调用
且仅调用一次。
基本调用顺序就是,执行当前类的load方法,必定先调用super的load方法,如
果代码依赖其他程序库,那么程序库中得相关类的load方法也会先执行。类load
方法执行完成后,会执行相应的分类的load的方法。
但是如果在一个程序库中得若干个class,却没法确定load顺序,所以load方法不
建议使用其他class。
load方法在调用的时候,app会阻塞,所以一定要轻!
应用程序会阻塞并把所有类的load方法都执行完,才能继续。
load方法直接使用函数内存地址的方式(*load_method)(cls, SEL_load)调用的,
而不是使用发送消息 objc_msgSend 的方式。
因此:load方法不遵循继承规则:如果一个class本身没有实现load方法,那么无
论其各级super是否实现load,都不会调用;
同时:当一个类和它的分类都实现了 +load 方法时,两个方法都会被调用。
所以:像method swizzling这种操作会放在load里面进行。
load方法调用时,程序甚至没有autoreleasepool
initialize方法:首次使用该class前调用,且只有1次。
和load方法相比,他是“lazy”调用的,也就是类或它的子类收到第一条消息之前
被调用的,这里所指的消息包括实例方法和类方法的调用。。
可以安全使用任何class,因为它们都已经load过了。
initialize方法执行一定在thread-safe environment,也就是说会阻塞所有线
程。
initialize会走和objc_msgSend一样的消息发送原则,也就是会有覆盖。
实际编译器调用时,父类的会优先于子类调用。
警告
消除方法弃用警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// 这里写出现警告的代码
#pragma clang diagnostic pop
1
int 和 NSInteger
应使用NSUInteger,而非int。 这样做的是基于64-bit 适配考虑
规范
NSArray使用copy , NSMutableArray 使用strong
浅复制和深复制
2
#import不会重复导入,
#include 导入 c,c++头文件
@class运行时导入,保证编译可以通过,避免循环引用
Objective-C中堆
存放oc对象,需要手动申请和释放内存(ARC无需手动释放)
Objective-C中栈
栈由系统自动分配,一般存放非oc对象的基本类型数据,例如int,float,不需
要手动管理
self
self调用方法时,会优先在当前类的方法列表中寻找方法, 没有再去父类(.h声明)
找
super
直接去父类找方法
注意 [self class]; 和 [super class]; 返回都是当前子类 , 区别是寻找方法时是否
在当前子类寻找
3
const
确定后值不能修改 , 定义该 const 变量时,通常需要对它进行初始化,因为以后
就没有机会再去改变它了
//声明一个int类型的变量a,设置后不能再修改(下面两种方式等价)
int const a = 10;
const int a = 10;
判断p 和p是只读还是变量,关键是看const在谁前面。如果只在p前面,那么p只
读,p还是变量;如果在p前面,那么p只读 ,p变量 :
int const *p // *p只读 ;p变量
int * const p // *p变量 ; p只读
const int * const p //p和*p都只读
int const * const p //p和*p都只读
volatile
可能被意想不到的修改, 因此优化器在用到这个变量时必须每次都小心地重新读
取这个变量的值,而不是使用保存在寄存器里的备份
static
static标记的变量会存储到全局变量区,生命周期和程序相同
节省内存。静态变量只存储一处,但供所有该类的对象使用
它的值是可以更新的 (修改后所有访问都是修改后的)
.m内声明: 只在该类内部使用, .h声明:所有子类或者导入类可使用
static变量:线程共享,非线程安全
static方法: 1. 内部不引用对象,只有局部变量 是安全的。 3. 引用方法外部变
量,self变量,是线程非安全的。
extern
在.h声明, 作用域是整个程序 : 比如
//.h中声明一个字符串常量
extern NSString * const testName;
//.m中实现
NSString * const testName = @"小明";
属性
@property (nonatomic,strong) UITextField *username;
可以使用“.”语法访问变量
类属性 :
编译器会自动生成set和get方法
分类属性 :
默认没有set和get方法
需要runtime进行方法绑定,手动实现set,get方法, 但是其他方法也要实现,不然不
要调用
id/instancetype类型区别 ?
id : 编译时无法确认对象真实类型, 只有等到运行时才能确认
instancetype :
编译时就能确认对象真实类型时使用
比如 类内部自身对象初始化返回
实例变量
@interface BaseViewController : UIViewController {
UITextField *username2;
}
只能在类内部访问
不能使用“.”语法
需要手动实现set和get方法
atomic 和 nonatomic
atomic原子性, 对set方法加锁, 不是绝对安全的
nonatomic 无锁, 效率高
资源竞争需要手动加锁
读写控制
readonly
只读,编译器只提供get方法
readwrite
读写,编译器提供set和get方法
内存管理
assign
修饰oc对象的基础类型
指针弱引用(引用计数不变)
如果修饰oc非基础对象, 不会自动释放指针,从而导致野指针问题, 不建议(自动
引用计数不管理assign)
weak
弱引用修饰oc非基础对象
weak修饰的变量在销毁后,自动将指针置为nil,避免野指针
避免循环引用时需要weak
常见“delegate,block”
retain
修饰oc非基础对象
强引用,引用计数+1
strong
ARC替代retain
storyboard 使用IBOutlet修饰的控件
以前默认是weak,现在是strong
copy
只是创建内存地址指针, 不会重新创建新对象
新对象引用计数=1
mutableCopy
创建新内存地址
新对象引用计数=1
类工厂方法
快速创建对象的的类方法,可以直接返回一个初始化好的对象
UIButton类中的 + (instancetype) buttonWithType:类工厂方法
方法重载
方法重载 : 方法名称一样,参数名称不一样
OC没有方法重载, 不允许相同方法,不同参数
- (void) useName:(NSString *)name;
- (void) useName:(NSString *)name2;
上面两种方法不能存在一个类里
OC是消息转发机制, 使用useName:来区分方法, 无法区分参数名称
OC继承
OC是单继承
多继承需要通过组合,协议,分类实现类似多继承
不能实现多继承?
OC的消息机制,名字查找发生在运行时,而不是编译时,不能解决多个基类的二
义性
分类Category
不破坏已有类的情况下,为该类添加新方法的一种方式
会创建新的类文件, xxx (xxx)形式
//分类的定义,结构体
typedef struct category_t {
const char *name;//分类名
classref_t cls;//扩展的类
struct method_list_t *instanceMethods;//实例方法列表
struct method_list_t *classMethods;//类方法列表
struct protocol_list_t *protocols;//协议列表
struct property_list_t *instanceProperties;//属性列表
} category_t;
默认只支持类方法, 默认不支持属性方法和属性对象(不会自动创建set和get等方
法)
Category新建的类方法和系统方法重名,会覆盖系统方法
加载步骤 :
(1)_objc_init runtime入口函数,初始化
(2)map_images 加锁
(3)map_images_nolock 完成类的注册,初始化,及load方法加载
(4)_read_images 完成类的加载,协议的加载,类别的加载等工作
(5)remethodizeClass 这一步非常关键,它将类别绑定到目标类上
(6)attachCategories 这是最重要的一步,将类别中的方法,属性绑定到目标
类
(7)attachLists 将目标类中的方法和分类中的方法放到一个列表中
+load 加载
不是继承, 所有类都会实现+load方法
加载顺序 : 父类,子类,分类
通过函数指针调用,runtime运行时调用,较早
initialize方法可以继承,是通过消息传递调用的,第一次收到消息时调用,较晚
扩展
破坏类结构,直接添加方法和属性
UIViewController的生命周期
1、 alloc
创建对象,分配空间
2、init (initWithNibName|initWithCoder)
初始化对象,初始化数据
3、awakeFromNib
所有视图的outlet和action已经连接,但还没有被确定。
4、loadView
完成一些关键view的初始化工作,加载view。
5、viewDidLoad
载入完成,可以进行自定义数据以及动态创建其他控件
6、viewWillAppear
视图将出现在屏幕之前
7、viewWillLayoutSubviews
将要对子视图进行调整
8、viewDidLayoutSubviews
对子视图进行调整完毕
9、viewDidAppear
视图已在屏幕上渲染完成
10、viewWillDisappear
视图将被从屏幕上移除
11、viewDidDisappear
视图已经被从屏幕上移除
12、dealloc
视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放
APP生命周期
1、程序启动:
状态由Not running -> Inactive -> Active
willFinishLaunchingWithOptions
didFinishLaunchingWithOptions
applicationDidBecomeActive
2、点击home键|锁屏:
由Active -> Inactive -> Backgroud
applicationWillResignActive
applicationDidEnterBackground
3、重新进入前台:
Backgroud -> Inactive -> Active applicationWillEnterForeground
applicationDidBecomeActive
4、在前台,双击home键,手动杀掉APP:
Active -> Inactive -> Backgroud -> end
applicationWillResignActive
applicationDidEnterBackground
applicationWillTerminate
5、当URL到达时,如果你的应用没在正在运行,则会被启动并且移到前台运行以
打开URL
application:didFinishLaunchingWithOptions:
application:openURL:sourceApplication:
applicationDidBecomeActive
6、当URL到达时,如果你的应用正在background运行或被suspended,它将会
被移到前台以打开URL
applicationWillEnterForeground
application:openURL:sourceApplication:
applicationDidBecomeActive