目录
1. @修饰符
2. 类别和扩展
3. const , #define , typedef , extern , static
5. self.name和_name的区别
6. id与instancetype与void *的区别
7. nil、Nil、Null、NSNull的区别
8. #include 和 #import 的区别
10. initialize 和 load
11. 延迟加载 和 异步加载
13. 指针
14. 架构模式
1. @修饰符
- @property修饰符
详情见内存管理篇
- 修饰协议中方法(@optional、@required)
@optional : 可选实现方法
@required : 必须实现方法(默认)
protocol协议
只有方法声明,没有方法实现。
遵循协议(则拥有方法的声明),就需要实现必须实现的方法(@required 修饰的方法)。
- 修饰属性(@dynamic、@synthesize)
@dynamic 属性;
其getter和setter方法编译器是不会自动生成,需程序员手动实现,否则使用时崩溃.
@synthesize 属性;(默认)
其getter和setter方法编译器是会自动生成,不需手动实现。
当重新父类属性的get方法时时,必须手动写 @synthesize。
@synthesize headView = _headView;
当遵守的协议中有属性,必须手动写 @synthesize。
@synthesize name;
- 提前声明类(@class)
@class 类名;
作用:用于在.h中提前声明一个类,提高编译效率;.m依旧要引入该类#import""
- 修饰属性和方法的使用范围(@public、@private、@protected、@package)
@public : 所有地方都能使用
@private : 仅本类可用
@protected : 本类及子类
@package : 本应用程序包
2. 类别和扩展
- 类别 Category
1、只能添加方法,不能添加属性。不能添加成员变量(回报编译错误)。
因为添加属性时,不会自动生成set、get方法。但可使用runtime动态运行时机制来动态添加(添加的属性只有在运行时才存在)。
2、会覆盖普通类中同名的方法。
级别高于普通类。本质是因为会先编译普通类再编译类别,所以会覆盖普通类。
若两个类别都实现了同名方法,则决定于头文件的添加顺序(Build Phases|Compile Sources排在下边的优先级高),通常命名方法的时候加前缀来避免这种情况发生。
注意:load方法除外,会先执行原类的load方法,再执行分类的load方法。
3、可以在不改变且不知道原类代码的情况下给类添加新方法。
4、可以将类的实现分散到不同的文件或框架中便于维护。
5、可以对外暴露私有方法。
例1
cmd+N 选Objective-C file新建类别文件(例:)
文件NSArray+YTCusArray.h
#import
@interface NSArray (YTCusArray)
@end
文件NSArray+YTCusArray.m
#import "NSArray+YTCusArray.h"
@implementation NSArray (YTCusArray)
@end
- 扩展
只能存在于.m文件中,用于添加私有属性和方法以及成员变量。
将.h中定义的readOnly属性,在.m中重新定义为readWrite。
来达到:在类的内部就可以直接修改它的值,然而外部依然不能调用 setter 方法来修改。
例1
@interface Person(){
NSString *name;
}
@property (nonatomic,readwrite) NSArray *contentArray;
-(void)run;
@end
3. const , #define , typedef,extern,static
- const
用来定义常量(编译时会检查数据类型。存放在常量表中)
const int a=10; int const a=10; 无影响
const Person *p; Person const *p; *p不可变 p可变
Person *const p; p不可变 *p可变
- 宏定义 #define
#define
宏定义(预编译指令,在预处理阶段直接替换,不存在于常量表中),将前者替换成后者,编译时不检查数据类型
#define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
- typdedef
typedef int MyIn; // typedef 旧 新;
给已有类型起别名,检查数据类型
1. 便捷使用:枚举,结构体,block;
2. 安全:给系统类型重命名(起到一定的混淆作用)
- extern
修饰 全局变量且没有用static 修饰时,其作用域为整个项目文件
.h
extern NSString *const name;
.m
NSString *const name=@"hello";
其他文件中
导入该文件或者extern NSString *const name;
即可使用
- static
static int age = 20;
修饰局部变量时:程序运行期间只会初始化一次 并且 直到整个程序结束时才被销毁
修饰全局变量时:作用域仅限于本类
/*
1).函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
2).在模块内的 static 全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
3).在模块内的 static 函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;
4).在类中的 static 成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
5).在类中的 static 成员函数属于整个类所拥有,这个函数不接收 this 指针,因而只能访问类的static 成员变量。
*/
- 比较
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";
5. self.name和_name的区别、self.name=nil和[self.name release]的区别
self.name和_name的区别:
self.name会调用setget方法修改变量,而_name会直接修改变量。
self.name=nil和[self.name release]的区别:
self.name是通过set方法将name属性置为nil,[name release] 只是将name的引用计数减1,此时若name的引用计数不为0,还可以访问。
6. id与instancetype与void *的区别
id可以指向任何类类型的对象(不需要*)
instanceType只能作为返回值,返回:和该方法所在类相同类型的对象
void*指无类型指针(等同于id),指向任意类类型的对象。
7. nil、Nil、Null、NSNull的区别
nil :表示空对象,调用nil不会崩溃
Nil :表示空类
Null :表示空指针,不指向任何内存地址
NSNULL :表示一个空的集合对象
8. #include 和 #import 的区别
#include 会重复导入头文件
#import 不会重复导入头文件
#import<> 包含系统头文件(从系统库目录中查找)
#import"" 包含自定义头文件(查找自定义头文件)
9. 简便构造方法
如NSNumber的 + numberWithBool: + numberWithChar: + numberWithDouble: + numberWithFloat: + numberWithInt:
10. initialize 和 load
- load、initialize
NSObject(绝大多数类都直接或间接继承NSObject)
+(void)load{}
应用启动后会 加载所有类的load方法(会在main之前执行)。
子类的 +load 方法会在它的所有父类的 +load 方法之后执行,而分类的 +load 方法会在它的主类的 +load 方法之后执行。但是不同的类之间的 +load 方法的调用顺序是不确定的。
load 方法不会被类自动继承, 每一个类中的 load 方法都不需要像 viewDidLoad 方法一样调用父类的方法。
可用来交换系统方法。
+(void)initialize{[super initialize];}
第一次使用该类时调用(会在init方法前调用)
类别优先级高,会覆盖。子类没有实现,会调用父类的。
- View
// 构造(初始化)
-(instancetype)init{}
-(instancetype)initWithFrame:(CGRect)frame;
// 销毁
-(void)delloc{};
@interface CusView : UIView
@end
@implementation CusView
/**
[CusView new]、[[CusView alloc]init] 会首先调用initWithFrame方法,然后调用init方法。
[[CusView alloc]initWithFrame:CGRectMake(0, 0, 100, 200)] 只会调用initWithFrame方法。
注意:
在创建基类的时候,不要initWithFrame和init方法中重复调用同一方法,只需放在initWithFrame中调用。
*/
-(instancetype)initWithFrame:(CGRect)frame{
self=[super initWithFrame:frame];
if(self){
NSLog(@"");
}
return self;
}
-(instancetype)init{
self=[super init];
if(self){
NSLog(@"");
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)coder{
self=[super initWithCoder:coder];
if(self){
NSLog(@"");
}
return self;
}
// 销毁时调用
-(void)dealloc{
NSLog(@"");
}
@end
- UIViewController
待续。。。
11. 延迟加载 和 异步加载
延迟加载:
重写get方法,用到时才加载
避免瞬时内存过高
异步加载:
避免线程堵塞
13. 指针
int a[10]; // 10个int 元素
int *a[10]; // 10个指向int的指针 元素
int (*a)[10]; // 指向10个int元素数组 指针
int (*a[10])(int); // 10个指向函数(返回int参数int)的指针 元素
14. 架构模式
常用
MVC
MVVM
MVC模式
M 表示Model模型层,数据模型(用来存储和传递数据)
V 表示View视图层,界面视图(用来显示数据)
C 表示Controller控制层,UIController(用来将数据显示到视图上,并负责处理用户交互,以及其他业务逻辑)
Model和View层不能直接通信
MVVM模式
M 表示Model模型层,数据模型(用来存储和传递数据)
V 表示View视图层,界面UI(用来显示数据)
VM 表示模型数据处理层,用来请求网络获取数据,并转换为视图所需的数据格式(简化C)
C 表示Controller控制层,UIController(用来将数据显示到视图上,处理用户交互,以及其他业务逻辑)