id 与 instancetype 区别
1.id 可以当返回值类并且可以声明对象
2.instancetype 只可以当返回值类型
3.instancetype 返回和方法所在类相同类型的对象,id返回未知类型的对象(instancetype 会对返回值类型做一个检查,检查你这个返回值是不是当前类类型)
4.自定义初始化方法,返回值类型如果写成id,编译器会自动转换成instancetype
// instancetype 会对返回值类型做一个检查,检查你这个返回值是不是当前类类型
- (instancetype)createCatObjToo {
Cat *cat = [[Cat alloc] init];
return cat;
// 返回name的话,会有警告,用id的话就不会有警告
// return _name;
}
多态的概念:
多态是指一种类型,具有多重表现形态。不同的子类继承同一个父类,这些子类可以看做是同一类型,子类覆盖父类的方法, 每个子类实现的功能不相同,这就是多态的表现。
多态要点:
(1)必须存在继承关系
(2)子类重写父类方法
(3)父类声明的变量指向子类对象
NSString的创建方法:
#import
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString *str1 = [[NSString alloc] initWithString:@"string"];
NSString *str2 = [NSString stringWithString:@"string"];
NSString *str3 = [[NSString alloc] initWithFormat:@"%@", @"string"];
NSString *str4 = [NSString stringWithFormat:@"%@", @"string"];
NSLog(@"str1指向:%p", str1);
NSLog(@"str2指向:%p", str2);
NSLog(@"str3指向:%p", str3);
NSLog(@"str4指向:%p", str4);
}
return 0;
}
运行结果:
从运行结果中可以str1与str2存储的地址是一样的,str3与str4存储的地址是一样的.由此,对NSString对象存储区域进行了以下猜测:
1.类方法stringWithString 调用了 [[NSString alloc] initWithString:@”string”]
2.类方法stringWithString 也许会先判断是否已经生成了字符串对象,如果生成了直接指向
3.NSString对象最终指向常量区
4.NSString不同源的创建方法,指向不同的内存地址
1.给现有的类,扩展新方法,在我不知道源码的情况,去修改
2.可以很好的代码规划,把类的实现按功能模块分为不同的文件,看类目的名字就知道这里的方法的功能
不能添加新的属性(官方文档规定;实际上:利用static,在大括号外面定义一个静态变量,再写set,get方法,可以实现)
1.如果是用XCODE內建添加延展的方式,不需要在person.h里声明一次方法,然后方法的实现在person.m实现
2.也可以自己使用关键字@interface来创建延展,但是方法如果没有在person.h里声明,调用则需要performselector:这个方法来调用方法
注 : 延展是能添加属性,但是必须在person.m里添加
1.类目和延展:为现有的类增加方法,方便代码管理.用Xcode方法创建延展只有一个.h,文件,必须在原始类的.m文件中写方法的实现.也可以自己直接在原始类的.m文件中写延展.这样连方法的申明都不能被外部看到.
2.类目是否可以为类增加属性: 不行.
苹果官方规定不可以.实际上:利用static,在大括号外面定义一个静态变量,再写set,get方法,可以实现.
3.延展是否可以为类目增加属性:可以.
用Xcode方法创建延展时不行.自己在现有类的.m文件中写
1.协议的概念:协议是定义了一系列的规则,目的是为了约束签订这个协议的对象,遵守,实现这些规则。
2.所有的协议有一基协议,就是NSObject协议
3.如果想一个类拥有多种不同类型的行为,可以使用协议,因为在OC里可以签署多个协议
4.关键字:@required修饰的方法必须实现,关键字会被子协议一同继承
@optional修饰的方法可选实现
默认状态下为@required修饰
协议的一些方法:
// 1.判断一个对象是否签署了一个协议
BOOL result1 = [stu conformsToProtocol:@protocol(WXHLProtocol)];
// 2.判断一个对象是否实现了方法
BOOL result2 = [stu respondsToSelector:@selector(dontLate)];
变量:作用域(哪里能使用该变量) 生存周期(变量内存从分配到回收过程)
(1) 局部变量,栈区-动态区:作用域-模块中 生存周期-从模块开始到模块结束
(2) 全局变量,静态区:作用域-全局 生存周期-从程序开始到程序结束
(3) static 局部变量,静态区:作用域-局部, 生存周期-从程序开始到程序结束
(4) static 全局变量: 该全局变量只能在本文件使用
(5) static 函数:只能在本文件调用该函数
(1) [NSSting sttringWithUTF8String: str1] 把C字符串转成0C字符串,UTF8是一个编码格式.
(2) NSComparisonResult result =[s1 caseInsensitiveCompare:s2];
忽略大小写比较字符串
NSComparisonResult result = [s1 compare :s2];
不忽略大小写比较
(3) [str1 characterAtIndex:5] 根据下标取字符
数组元素调用各自方法,强行调用
(1)runtime机制,没有在.h中声明的方法,可以使用下面的方法调用
[person performSelector:@selector(test2)];
(2)让数组中的元素调用自己实例里面的方法
NSArray *array10 = @[p1, p2, p3, p4, p5];
[array10 makeObjectsPerformSelector:@selector(doSomeThing)];
@class的使用
在.h里用到其他类时,如果使用#import. 当另一个类也用到这个类时,也使用#import,就会相互导入而出错.
所以在.h里用到其他类使用@class告诉编译器有这么一个类,具体这个类怎么定义的一无所知.在.m文件里使用#import.
如果就单单定义常量说的话:
1. const 定义的常数是变量 也带类型
2. #define 定义的只是个常数 不带类型。
如果要更多的比较,就很多了
1.const定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define定义的宏常量在内存中有若干个拷贝。
2.#define宏是在预编译阶段进行替换,而const修饰的只读变量是在编译的时候确定其值。
3.#define宏没有类型,而const修饰的只读变量具有特定的类型
4.const修饰变量的可变性
这里有一个记忆和理解的方法:
先忽略类型名(编译器解析的时候也是忽略类型名),我们看const离哪个近。”近水楼台先得月”,离谁近就修饰谁。
判断时忽略括号中的类型
const (int) *p; //const修饰*p,*p是指针指向的对象,不可变
(int) const *p; //const修饰*p,*p是指针指向的对象,不可变
(int)*const p; //const修饰p,p不可变,p指向的对象可变
const (int) *const p; //前一个const修饰*p,后一个const修饰p,指针p和p指向的对象都不可变
总的来说:
const:有数据类型,编译进行安全检查,可调试
define:宏,不考虑数据类型,没有安检,不能调试