黑马程序员——OC核心语法
来源:互联网 发布:5s手机4g网络用不了 编辑:程序博客网 时间:2024/05/03 21:16
点语法
简单的一句话,点语法的本质就是方法调用。
set方法[p setAge:10];
用点语法可以表达为:p.age = 10;
;get方法int a = p.age;
用点语法可以表达为:[p age];
。
在使用点语法的时候我们需要注意逻辑关系,在方法的声明中引入不当的点语法会造成死循环:
- (void)setAge:(int)age{ // _age = age; self.age = age; }- (int)age{ // return _age; return self.age;}
在这个程序中,两个点语法都会造成死循环的产生。第一个点语法可以写成[self setAge:age];
,第二个点语法可以写成[self age];
。
成员变量的作用域
成员变量的作用域有四种方式定义
1> @public : 在任何地方都能直接访问对象的成员变量;
2> @private : 只能在当前类的对象方法中直接访问,在@implementation中默认的就是@private;
3> @protected : 可以在当前类及其子类的对象方法中直接访问 在@interface中默认就是@protected;
4> 第四种是不常用的一种方式,@package : 只要处在同一个框架中,就能直接访问对象的成员变量。
除了作用域我们还需要注意的是在@implementation中不能定义和@interface中同名的成员变量;同时在main函数后面的成员变量都不能直接访问的。
@property和@synthesize
首先我们做一个练习:
设计一个类Circle,用来表示二维平面中的圆
1> 属性
* double _radius (半径)
* Point2D *_point (圆心)
2> 方法
* 属性相应的set和get方法
* 设计一个对象判断跟其他圆是否重叠(重叠返回YES,否则返回NO)
* 设计一个类方法判断两个圆是否重叠(重叠返回YES,否则返回NO)
我们可以先设计一个点作为圆心,通过圆心距离和半径和的大小来判断圆是否重叠
#import <Foundation/Foundation.h>#import <math.h>// 点@interface Point2D : NSObject{ double _x; double _y;}// x的getter和setter- (void)setX:(double)x;- (double)x;// y的getter和setter- (void)setY:(double)y;- (double)y;//同时设置x和y- (void)setX:(double)x andY:(double)y;// 方法对象计算和其他点得距离- (double)distanceWithOther:(Point2D *)other;// 类方法计算两个点之间的距离+ (double)distanceBetweenPoint1:(Point2D *)p1 andPoint2:(Point2D *)p2;@end@implementation Point2D// x的getter和setter的实现- (void)setX:(double)x{ _x = x;}- (double)x{ return _x;}//y的getter和setter的实现- (void)setY:(double)y{ _y = y;}- (double)y{ return _y;}//同时设置x和y的实现- (void)setX:(double)x andY:(double)y{ _x = x; _y = y;}- (double)distanceWithOther:(Point2D *)other{ return [Point2D distanceBetweenPoint1:self andPoint2:other];}+ (double)distanceBetweenPoint1:(Point2D *)p1 andPoint2:(Point2D *)p2{ // (x1-x2)的平方 double X = pow(([p1 x] - [p2 x]), 2); // (y1-y2)的平方 double Y = pow(([p1 y] - [p2 y]), 2); // 对两个平方和开根号 return sqrt(X + Y);}@end// 圆@interface Circle : NSObject{ double _radius; Point2D *_point;}// 半径的getter和setter- (void)setRadius:(double)radius;- (double)radius;// 圆心的getter和setter- (void)setPoint:(Point2D *)point;- (Point2D *)point;// 对象方法判断和其他圆是否重叠- (BOOL)intersectWithOther:(Circle *)other;// 类方法判断和其他圆是否重叠+ (BOOL)isIntersectCircle1:(Circle *)c1 andCircle2:(Circle *)c2;@end@implementation Circle// 半径getter和setter的实现- (void)setRadius:(double)radius{ _radius = radius;}- (double)radius{ return _radius;}// 圆心getter和setter的实现- (void)setPoint:(Point2D *)point{ _point = point;}- (Point2D *)point{ return _point;}// 对象方法实现- (BOOL)intersectWithOther:(Circle *)other{ return [Circle isIntersectCircle1:self andCircle2:other];}// 类方法实现+ (BOOL)isIntersectCircle1:(Circle *)c1 andCircle2:(Circle *)c2{ // 两个圆心 Point2D *p1 = [c1 point]; Point2D *p2 = [c2 point]; // 两个圆心的距离 double distance = [Point2D distanceBetweenPoint1:p1 andPoint2:p2]; // 半径的和 double sumOfRadius = [c1 radius] + [c2 radius]; return distance < sumOfRadius;}@endint main(){ Circle *c1 = [Circle new]; // 设置半径 [c1 setRadius:5]; // 设置圆心 Point2D *p1 = [Point2D new]; [p1 setX:5 andY:5]; [c1 setPoint:p1]; Circle *c2 = [Circle new]; // 设置半径 [c2 setRadius:4]; // 设置圆心 Point2D *p2 = [Point2D new]; [p2 setX:8 andY:6]; [c2 setPoint:p2]; BOOL i1 = [c1 intersectWithOther:c2]; BOOL i2 = [Circle isIntersectCircle1:c1 andCircle2:c2]; NSLog(@"%d %d", i1, i2); return 0;}
虽然我们实现了功能,但是根据程序我们可以看出来,其中写了很多重复的代码,比如各成员变量的setter和getter方法。Xcode为了让我们不需要考虑这些重复代码,腾出心思来更好的考虑功能,特意定义了@property和@synthesize。
@property:可以自动生成某个成员变量的setter和getter声明。如下:
@property int age;//- (void)setAge:(int)age;//- (int)age;@property int height;//- (void)setHeight:(int)height;//- (int)height;
而@synthesize自动生成age的setter和getter实现,并且会访问_age这个成员变量,如下:
@synthesize age = _age;@synthesize height = _height;
同时当在@synthesize中访问某个不存在的成员变量时,系统会自动生成@private类型的变量。
虽然现在非常大的简化了我们的程序,但是并不是最简单的写法,最简单的可以写成:
@property int age;
这一行虽然简单,但是它又三个作用
第一、会自动生成setter和getter的方法
第二、会自动生成setter和getter的实现
第三、可以自动生成_age成员变量
根据这些我们就可以很大的简化程序,更好的去考虑功能。
构造方法
在说构造之前我们先说一个关键字id。id是一个万能指针,能指向\操作任何OC对象,id其实就是NSObject *,它只适用于OC对象。
在程序中初始化的成员变量默认都是0,有时候我们为了让对象创建出来,成员变量就会有一些固定的值,这个时候我们就用到了构造方法。
构造方法:用来初始化对象的方法,是个对象方法,-开头。
我们先来看一下完整地创建一个可用的对象是如何进行的:
Person *p = [Person new];
1.调用+alloc分配存储空间 Person *p1 = [Person alloc];
2.调用-init进行初始化 Person *p2 = [p1 init];
这两个步骤我们也可以等价为:
Person *p4 = [[Person alloc] init];
在”.m”文件中实现初始化,也就是重写init写法:
- (id)init{ // 1.一定要调用回super的init方法:初始化父类中声明的一些成员变量和其他属性 self = [super init]; // 当前对象 self // 2.如果对象初始化成功,才有必要进行接下来的初始化 if (self != nil) { // 初始化成功 _age = 10; } // 3.返回一个已经初始化完毕的对象 return self;}
以上的代码我们可以更加简化的书写:
- (id)init{ if(self = [super init]) { _age = 10; } return self;}
可以实现同样的初始化功能,而且更加简单便于记忆。不过这里可能有些人会对super有些忘记。super是直接调用父类的某个方法,当子类需要重写父类的方法的同时想保留父类的一些行为时使用super。
注意点:
1> 先调用父类的构造方法([super init])
2> 再进行子类内部成员变量的初始化
- 自定义构造方法
自定义构造方法的规范
1.一定是对象方法,一定以 - 开头
2.返回值一般是id类型
3.方法名一般以initWith开头
如:- (id)initWithName:(NSString *)name;
。
当在使用自定义构造方法的时候,需要注意一点:当子类的构造方法中包含父类的属性,在这个构造方法的实现中,父类的属性交给父类方法去处理,子类方法处理子类自己的属性,如下将name、age传递到父类方法中进行初始化:
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no{ if ( self = [super initWithName:name andAge:age]) { _no = no; } return self;}
分类-Category
分类的作用:在不改变原来类内容的基础上,可以为类增加一些方法。
- 格式
分类的声明
@interface 类名 (分类名称)// 方法声明@end
分类的实现
@implementation 类名 (分类名称)// 方法实现@end
分类可以将一个庞大的类可以由多个人来编写,更有利于团队合作。
分类的使用注意:
1.分类只能增加方法,不能增加成员变量
2.分类方法实现中可以访问原来类中声明的成员变量
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来的方法没法再使用
4.方法调用的优先级:分类(最后参与编译的分类优先) –> 原来类 –> 父类
除了上述的一些作用外,我们可以利用分类来写一些类没有的功能。
比如给NSString
增加一个类方法计算某个字符串内部英文字母的个数
增加一个对象方法计算当前字符串内部英文字母的个数
增加一个类方法比较两个字符串的长度,返回长度差
增加一个对象方法和其他字符串比较长度,返回长度差
声明:
#import <Foundation/Foundation.h>@interface NSString (NumberOfLetter)+ (int)letterNumberOfString:(NSString *)str;- (int)letterNumber;+ (int)compareLengthBetweenString1:(NSString *)str1 andString2:(NSString *)str2;- (int)compareLengthWithOther:(NSString *)other;@end
实现:
#import "NSString+NumberOfLetter.h"@implementation NSString (NumberOfLetter)+ (int)letterNumberOfString:(NSString *)str{ return [str letterNumber];}- (int)letterNumber{ int count = 0; for(int i = 0 ; i<self.length; i++) { // 取出i这个位置对应的字符 unichar c = [self characterAtIndex:i]; // 如果这个字符是英文字母 if( (c>='a' && c<='z') || (c>='A' && c<='Z') ) { count++; } } return count;}+ (int)compareLengthBetweenString1:(NSString *)str1 andString2:(NSString *)str2{ // return ([str1 length]-[str2 length]); return [str1 compareLengthWithOther:str2];}- (int)compareLengthWithOther:(NSString *)other{ return ([self length]-[other length]);}@end
类的本质
类也是一个对象
其实类也是一个对象,是Class类型的对象,简称“类对象”。Class类型的定义:typedef struct objc_class *Class;
;类名就代表着类对象,每个类只有一个类对象。+load和+initialize
1.当程序启动时,就会加载项目中所有的类和分类,而且加载后会调用每个类和分类的+load方法。只会调用一次。
2.当第一次使用某个类时,就会调用当前类的+initialize方法
3.先加载父类,再加载子类(先调用父类的+load方法,再调用子类的+load方法)
先初始化父类,再初始化子类(先调用父类的+initialize方法,再调用子类的+initialize方法)获取类对象的2种方式
Class c = [Person class]; // 类方法
或者
Person *p = [Person new];Class c2 = [p class]; // 对象方法
- 类对象调用类方法
Class c = [Person class];Person *p2 = [c new];
description方法
-description方法
使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出+description方法
使用NSLog和%@输出某个类对象时,会调用类对象+description方法,并拿到返回值进行输出
默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
1.会调用对象p的-description方法
2.拿到-description方法的返回值(NSString *)显示到屏幕上
3.-description方法默认返回的是“类名+内存地址”
如果在-description方法中使用NSLog打印self时会形成死循环:
- (NSString *)description{ // 下面代码会引发死循环 NSLog(@"%@", self);}
SEL
SEL其实是对方法的一种包装,将方法包装成一个SEL类型的数据,去找对应的方法地址。找到方法地址就可以调用方法。
- SEL对象的创建
SEL s = @selector(test);SEL s2 = NSSelectorFromString(@"test");
- SEL对象的其他用法
// 将SEL对象转为NSString对象NSString *str = NSStringFromSelector(@selector(test));Person *p = [Person new];// 调用对象p的test方法[p performSelector:@selector(test)];
_cmd代表着当前方法,使用时也会引发死循环:[self performSelector:_cmd];
。
- 黑马程序员——OC核心语法
- 黑马程序员——oc核心语法1
- 黑马程序员——OC语言核心语法
- 黑马程序员——OC语言基础篇---核心语法
- 黑马程序员——OC-10:核心语法
- 黑马程序员——[oc]核心语法1
- 黑马程序员——[OC]核心语法2
- 黑马程序员—OC语言基础—核心语法小结
- 黑马程序员——OC中的核心语法
- 黑马程序员——OC学习笔记04 核心语法
- 黑马程序员—04OC核心语法_01
- 黑马程序员—05OC核心语法_02
- 黑马程序员----OC核心语法
- 黑马程序员———OC基础语法(三)---核心语法(1)
- 黑马程序员———OC基础语法(四)---核心语法(2)
- 黑马程序员——OC核心语法点语法,成员变量,@property和@synthetic,构造方法
- 黑马程序员-10.OC的核心语法
- 黑马程序员6 oc核心语法
- java序列化
- centos smokeping nginx 部署,监控网络状况
- UVA1586
- Docker(1):Virtualbox Install Centos7 & Docker
- uva 11255 Necklace (polya)
- 黑马程序员——OC核心语法
- 网络号和主机号的计算
- 巧用Firefox检查代码是否安装正确
- 交换两个数 a和b,不使用任何中间变量
- In didFinishLaunchingWithOptions openUrl load 10 seconds
- 威佐夫博弈 && Fibonacci博弈
- 基于activex插件的海康大华网页版的播放(一)
- ArrayList vs. LinkedList vs. Vector
- Address already in use: JVM_Bind错误