------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
慢慢消化一起的内容,再继续往前!
本期目录:
1. 提醒与错误解决
2. Oc核心语法
3. xcode 使用技巧
4. 个人总结
一:提醒与错误解决
1.学习了构造方法,所以以后尽量不要new一个对象
2.重写init方法时尝试不去写[super init],编译运行都可以。但是,感觉不应该这样做。
3.今天运行程序明明逻辑对了,语法对了,但一直报错,仔细看发现时未全部保存(变灰未保存)
4.@property 是对变量自动生成set方法和get方法的声明,不是对变量的声明限制,所以不能放在@interface @end之间。
5.再次提醒:成员变量要以 _开头,因为标识只能以字母、数字、下划线开头,所以为了方便程序员直接交流也为了和局部变量区分。
6.为什么自定义方法名一般要以id类为返回类型?
7.%@打印oc对象,默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
8.方法命中如果有:,冒号也是方法的一部分,不加:是找不到方法。比如:(void)age:@“解决解决”;其中方法名为age:
二:核心语法
1,构造方法
1.构造方法:用来初始化对象的方法,是个对象方法,-开头
2.重写构造方法的目的:为了让对象创建出来,成员变量就会有一些固定的值
重写构造方法的注意点
1.先调用父类的构造方法([superinit]
2.再进行子类内部成员变量的初始化
3.注意init方法调用过程分析:
总结:
1.首先,student对象调用重写的init,而这个init会先调用父类init,这样依次类推
最后我们发现,NSObject的isa(指向对象创建的类)指向了Student类。
2.init方法调用时先完成父类初始化
3.自定义构造方法
讨论:如果我们想在程序初始化的时候给构造函数传入参数,一般的构造方式:(void)init;(继承自父类的方法,子类覆盖)。所以,我们可以去重写一个构造函数传入参 数,initWithxxx:(NSString *)xxx;。
自定义构造方法的规范
1.一定是对象方法,一定以- 开头
2.返回值一般是id的类型
3.方法名一般以init开头
错误体会:
我们可以看到:在父类Person中声明的@property NSString * name;可以再父类中使用_name成员变量(编译器自动生成)。但是,当我们在子类(Student类)中试图调用_name成员变量时,会出现“use of undeclaed identifier”(未定义的标识符)。原因在于,子类继承了父类的全部内容,但是_name 默认是@private。
解决策略:
2.category分类我们尝试这样做,子类调用继承的父类方法set方法来访问相应成员变量。
<span style="font-size:14px;">if(self = [super init]) { self.name = name;//name 为传入参数 self.age = age; }</span>
此时并未在Student类内部产生新的_name
分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法
使用注意:
1.分类只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用
4.方法调用的优先级:分类(最后参与编译的分类优先) --> 原来类 --> 父类
来看一段代码:
<span style="font-size:14px;">//main #import <Foundation/Foundation.h> #import "Person.h" #import "Person+MJ.h" #import "Person+JJ.h" int main() { Person *p = [[Person alloc] init]; //p.age = 10; // 优先去分类中查找,然后再去原来类中找,最后再去父类中找 [p test]; // [p study]; return 0; } </span>
Person.h<span style="font-size:14px;">#import <Foundation/Foundation.h> @interface Person : NSObject { int _age; // int age; int _height; double _weight; NSString *_name; } // @property:可以自动生成某个成员变量的setter和getter声明 @property int age; //- (void)setAge:(int)age; //- (int)age; @property int height; //- (void)setHeight:(int)height; //- (int)height; - (void)test; @property double weight; @property NSString *name; @end </span>
分类:Person+JJ.h<span style="font-size:18px;">#import "Person.h" @interface Person (JJ) - (void)test2; @end </span>
分类:Person+MJ.h
<span style="font-size:18px;">#import "Person.h" @interface Person (MJ) - (void)study; @end</span>
结果
分析:这里的执行过程式和编译器的编译顺序有关,通过查看编译顺序:
总结:可以看到我们可能不知道原来类的具体属性,但是我们可以再不妨碍原来类的基础上使用category产生类的补充,比如:我们想对系统提供的类NSString进行补充个性的方法,那么我们就可以使用category方式,这样将很大的提高编码的效率。
3.类的深究
Ø 其实类也是一个对象,是Class类型的对象,简称“类对象”
Ø Class类型的定义
typedef struct objc_class *Class;
Ø 类名就代表着类对象,每个类只有一个类对象
举个例子:
可以看到,内存中类只加载一次,其他的对象都是对这个类的指向(isa指向同一块区域),而内存中Person类本身也是以Class类的对象,所以Person也是个”特殊“的对象,类名就代表着类对象
<span style="font-size:18px;">//这里的代码是等价的 Person *p = [[Person alloc] init]; Person *p2 = [[Person alloc] init]; Class c = [p class]; Class c2 = [p2 class]; Class c3 = [Person class];//结果是相同的 </span>
类方法:load和initialize
Ø +load
在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法
先加载父类,再加载子类;也就是先调用父类的+load,再调用子类的+load
先加载元原始类,再加载分类
不管程序运行过程有没有用到这个类,都会调用+load加载
Ø +initialize
在第一次使用某个类时(比如创建对象等),就会调用一次+initialize方法
一个类只会调用一次+initialize方法,先调用父类的,再调用子类的
-description方法
使用原理:
1.使用NSLog和%@时,会调用对象的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
3.-description默认返回的是“类名+内存地址”
4,不要再description中使用self
-和+description方法:
-开头为对象的description方法
+开头是类对象的description,默认实现显示类名
NSLog的使用技巧
NSlog(@"%p",p);//对象地址
NSLog(@“%p",&p); //指针变量的地址
NSLog方法输出c语言字符串时是不能输出中文,所以可以使用printf
SEL类型
方法的存储位置
Ø 每个类的方法列表都存储在类对象中
Ø 每个方法都有一个与之对应的SEL类型的对象
Ø 根据一个SEL对象就可以找到方法的地址,进而调用方法
Ø SEL类型的定义
常用的SEL相关方法:
SEL s = @selector(test);
SEL s2 = NSSelectorFromString(@"test");
NSString *str = NSStringFromSelector(@selector(test));
调用:
[p performSelector:@selector(test3) withObject:@"jjjj"];
#import "Person.h" @implementation Person + (void)test { NSLog(@"test-----"); } - (void)test2 { // _cmd代表着当前方法 NSString *str = NSStringFromSelector(_cmd); // 会引发死循环 // [self performSelector:_cmd]; NSLog(@"调用了test2方法-----%@", str); } - (void)test3:(NSString *)abc { NSLog(@"test3-----%@", abc); } @end
3.xcode模板
如果我们不习惯已有command line 模板,我们可以通过xcode自己更改模板。同时,我们也可以自定义模板文件。
具体方法:
Finder -> applications ->xcode -> 右键 “显示包内容”
选择"TemplateInfor.plist“ 文件,这时我们就可以很轻松的完成更改。(推荐:用类似记事本打开后,command+f 搜索)
举一反三,我们可以发现可以更改:Class文件开始注释,文件名注释等等。
4.个人总结:
我有点明白oc执行效率高的原因了,因为他涉及了好多对底层的访问。不过最近发现,oc也有java类加载的思想,那么就很像jvm的模式了。所以有点疑问。
总体上,感觉oc语法和c和java都有不同,所以可能会比较难记忆,但代码多了就记住了。
------Java培训、Android培训、iOS培训、.Net培训、期待与您交