黑马程序员——OC的特有语法

1、 分类-Category

1. 基本用途:Category  分类是OC特有的语言,依赖于类。

? 如何在不改变原来类模型的前提下,给类扩充一些方法?有2种方式

● 继承

● 分类(Category)

2. 格式

? 分类的声明

@interface 类名 (分类名称)

// 方法声明

@end

? 分类的实现

@implementation 类名 (分类名称)

// 方法实现

@end

3. 好处

? 一个庞大的类可以分模块开发

? 一个庞大的类可以由多个人来编写,更有利于团队合作

?

4. 给系统自带的类添加分类

? 给NSString增加一个类方法:计算某个字符串中阿拉伯数字的个数

? 给NSString增加一个对象方法:计算当前字符串中阿拉伯数字的个数

5. 注意

? Category可以访问原始类的实例变量,但不能添加变量,只能添加方法。如果想添加变量,可以考虑通过继承创建子类

? Category可以实现原始类的方法,但不推荐这么做,因为它是直接替换掉原来的方法,这么做的后果是再也不能访问原来的方法

? 多个Category中如果实现了相同的方法,只有最后一个参与编译的才会有效

2、 类的本质

1. 类也是个对象

? 其实类也是一个对象,是Class类型的对象,简称“类对象”

? Class类型的定义

typedef struct objc_class *Class;

? 类名就代表着类对象,每个类只有一个类对象

2. +load和+initialize

? +load

● 在程序启动的时候会加载所有的类和分类,并调用所有类和分类的+load方法

● 先加载父类,再加载子类;也就是先调用父类的+load,再调用子类的+load

● 先加载元原始类,再加载分类

● 不管程序运行过程有没有用到这个类,都会调用+load加载

? +initialize

● 在第一次使用某个类时(比如创建对象等),就会调用一次+initialize方法

● 一个类只会调用一次+initialize方法,先调用父类的,再调用子类的

3. 获取类对象的2种方式

Class c = [Person class]; // 类方法

或者

Person *p = [Person new];

Class c2 = [p class]; // 对象方法

4. 类对象调用类方法

Class c = [Person class];

Person *p2 = [c new];

3、 description方法

1. -description对象方法

使用NSLog和%@输出某个对象时,会调用对象的-description方法,并拿到返回值进行输出

2. + description类方法

使用NSLog和%@输出某个类对象时,会调用类的+description方法,并拿到返回值进行输出

3. 修改NSLog的默认输出

● 重写-description或者+description方法即可

4. 死循环陷阱

● 如果在-description方法中使用NSLog打印self

 区别

+description方法决定了类对象的输出结果,即类本身

-description方法决定了实例对象的输出结果,即Person创建的对象。

 1 //
 2 //  main.m
 3 //  07-description方法
 4 //
 5 //  Created by apple on 13-8-8.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Person.h"
11
12
13 void test9()
14 {
15     // 输出当前函数名
16     NSLog(@"%s\n", __func__);
17 }
18
19 int main()
20 {
21     // 输出行号
22     NSLog(@"%d", __LINE__);
23
24     // NSLog输出C语言字符串的时候,不能有中文
25     // NSLog(@"%s", __FILE__);
26
27     // 输出源文件的名称
28     printf("%s\n", __FILE__);
29
30     test9();
31
32     Person *p = [[Person alloc] init];
33
34     // 指针变量的地址
35     NSLog(@"%p", &p);
36     // 对象的地址
37     NSLog(@"%p", p);
38     // <类名:对象地址>
39     NSLog(@"%@", p);
40
41     return 0;
42 }
43
44 void test2()
45 {
46     Class c = [Person class];
47
48     // 1.会调用类的+description方法
49     // 2.拿到+description方法的返回值(NSString *)显示到屏幕上
50     NSLog(@"%@", c);
51 }
52
53 void test1()
54 {
55     Person *p = [[Person alloc] init];
56     p.age = 20;
57     p.name = @"Jack";
58     // 默认情况下,利用NSLog和%@输出对象时,结果是:<类名:内存地址>
59
60     // 1.会调用对象p的-description方法
61     // 2.拿到-description方法的返回值(NSString *)显示到屏幕上
62     // 3.-description方法默认返回的是“类名+内存地址”
63     NSLog(@"%@", p);
64
65     //Person *p2 = [[Person alloc] init];
66     //NSLog(@"%@", p2);
67
68     //NSString *name = @"Rose";
69
70     //NSLog(@"我的名字是%@", name);
71
72     Person *p2 = [[Person alloc] init];
73     p2.age = 25;
74     p2.name = @"Jake";
75
76     NSLog(@"%@", p2);
77 }

4、 SEL

1. 方法的存储位置

? 每个类的方法列表都存储在类对象中

? 每个方法都有一个与之对应的SEL类型的对象

? 根据一个SEL对象就可以找到方法的地址,进而调用方法

? SEL类型的定义

typedef struct objc_selector ?*SEL;

2. SEL对象的创建

SEL s = @selector(test);

SEL s2 = NSSelectorFromString(@"test");

3. SEL对象的其他用法

// 将SEL对象转为NSString对象

NSString *str = NSStringFromSelector(@selector(test));

Person *p = [Person new];

// 调用对象p的test方法

[p performSelector:@selector(test)];

5、 NSLog输出增强

? __FILE__ :源代码文件名

? __LINE__ :NSLog代码在第几行

? _cmd :代表着当前方法的SEL

// 下面的代码会引发死循环

- (void)test {

[self performSelector:_cmd];

}

点语法

(一)认识点语法

声明一个Person类:

 1 //
 2 //  Person.h
 3 //  04-点语法
 4 //
 5 //  Created by apple on 13-8-7.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface Person : NSObject
12 {
13     int _age;
14     NSString *_name;
15 }
16
17 - (void)setAge:(int)age;
18 - (int)age;
19
20
21 - (void)setName:(NSString *)name;
22 - (NSString *)name;
23
24 @end

Person类的实现:

 1 //
 2 //  Person.m
 3 //  04-点语法
 4 //
 5 //  Created by apple on 13-8-7.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import "Person.h"
10
11 @implementation Person
12
13 - (void)setAge:(int)age
14 {
15     //_age = age;
16
17     NSLog(@"setAge:");
18
19     // 会引发死循环
20     //self.age = age; // [self setAge:age];
21 }
22
23 - (int)age
24 {
25     NSLog(@"age");
26     return _age;
27     // 会引发死循环
28     //return self.age;// [self age];
29 }
30
31 - (void)setName:(NSString *)name
32 {
33     _name = name;
34 }
35
36 - (NSString *)name
37 {
38     return _name;
39 }
40
41 @end

点语法的使用:

 1 //
 2 //  main.m
 3 //  04-点语法
 4 //
 5 //  Created by apple on 13-8-7.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Person.h"
11
12 int main(int argc, const char * argv[])
13 {
14     Person *p = [Person new];
15
16     // 点语法的本质还是方法调用
17     p.age = 10; // [p setAge:10];
18
19     int a = p.age; // [p age];
20
21
22     p.name = @"Jack";
23
24     NSString *s = p.name;
25
26     NSLog(@"%@", s);
27
28     return 0;
29 }

二)点语法的作用

OC设计点语法的目的,是为了让其他语言的开发者可以很快的上手OC语言开发,使用点语法,让它和其他面向对象的语言如java很像。

(三)点语法的本质

点语法的本质是方法的调用,而不是访问成员变量,当使用点语法时,编译器会自动展开成相应的方法。切记点语法的本质是转换成相应的set和get方法,如果没有set和get方法,则不能使用点语法。

如:

Stu.age=10;展开为:[stu setAge:10];

int  a=stu.age;展开为:[stu age];

编译器如何知道是set方法还是get方法?主要是看赋值(可以使用断点调试来查看)。

在OC中访问成员变量只有一种方式即使用-> 如stu->age,这种情况要求在@public的前提下。

(四)点语法的使用注意

下面的使用方式是一个死循环:

  (1)在set方法中,self.age=age;相当于是[self setAge:age];

(2)在get方法中,return self.age;相当于是[self age];

 1 点语法(找出不合理的地方)
 2 #import <Foundation/Foundation.h>
 3 @interface Person : NSObject
 4 {
 5     int _age;
 6 }
 7 - (void)setAge:(int)age;
 8 - (int)age;
 9 @end
10
11 @implementation Person
12 {
13     int _age;
14 }
15 - (void)setAge:(int)age
16 {
17     _age = age;
18     // 会引发死循环
19     // self.age = age;
20 }
21 - (int)age
22 {
23     return _age;
24     // 会引发死循环
25     // return self.age;
26 }
27 @end
28
29 // 2个不合理

二、变量作用域

(一)变量的作用域主要分为四种:

(1)@public (公开的)在有对象的前提下,任何地方都可以直接访问。

(2)@protected (受保护的)只能在当前类和子类的对象方法中访问

(3)@private (私有的)只能在当前类的对象方法中才能直接访问

(4)@package (框架级别的)作用域介于私有和公开之间,只要处于同一个框架中就可以直接通过变量名访问

 1 #import <Foundation/Foundation.h>
 2
 3 @interface Person : NSObject
 4 {
 5     int _no;
 6
 7     @public // 在任何地方都能直接访问对象的成员变量
 8     int _age;
 9
10
11     @private  // 只能在当前类的对象方法中直接访问
12     int _height;
13
14     @protected // 能在当前类和子类的对象方法中直接访问
15     int _weight;
16     int _money;
17 }
18
19 - (void)setHeight:(int)height;
20 - (int)height;
21
22 - (void)test;
23 @end

(二)使用注意和补充

(1)在类的实现即.m文件中也可以声明成员变量,但是因为在其他文件中通常都只是包含头文件而不会包含实现文件,所以在这里声明的成员变量是@private的。在.m中定义的成员变量不能喝它的头文件.h中的成员变量同名,在这期间使用@public等关键字也是徒劳的。

(2)在@interface  @end之间声明的成员变量如果不做特别的说明,那么其默认是protected的。

(3)一个类继承了另一个类,那么就拥有了父类的所有成员变量和方法,注意所有的成员变量它都拥有,只是有的它不能直接访问。

 

@property @synthesize关键字

注意:这两个关键字是编译器特性,让xcode可以自动生成getter和setter的声明和实现。

(一)@property 关键字

@property 关键字可以自动生成某个成员变量的setter和getter方法的声明

@property int age;

编译时遇到这一行,则自动扩展成下面两句:

- (void)setAge:(int)age;

- (int)age;

(二)@synthesize关键字

@synthesize关键字帮助生成成员变量的setter和getter方法的实现。

语法:@synthesize age=_age;

相当于下面的代码:

- (void)setAge:(int)age

{

_age=age;

}

- (int)age

{

Return _age;

}

(三)关键字的使用和使用注意

类的声明部分:

类的实现部分:

测试程序:

新版本中:

类的声明部分:

类的实现部分:

测试程序:

(1)在老式的代码中,@property只能写在@interface  @end中,@synthesize只能写在@implementation   @end中,自从xcode 4.4后,@property就独揽了@property和@synthesize的功能。

(2)@property int age;这句话完成了3个功能:1)生成_age成员变量的get和set方法的声明;2)生成_age成员变量set和get方法的实现;3)生成一个_age的成员变量。

注意:这种方式生成的成员变量是private的。

(3)可以通过在{}中加上int _age;显示的声明_age为protected的。

(4)原则:get和set方法同变量一样,如果你自己定义了,那么就使用你已经定义的,如果没有定义,那么就自动生成一个。

(5)手动实现:

1)如果手动实现了set方法,那么编译器就只生成get方法和成员变量;

2)如果手动实现了get方法,那么编译器就只生成set方法和成员变量;

3)如果set和get方法都是手动实现的,那么编译器将不会生成成员变量。

   

Id

id 是一种类型,万能指针,能够指向\操作任何的对象。

注意:在id的定义中,已经包好了*号。Id指针只能指向os的对象。

id 类型的定义

Typedef struct objc object{

Class isa;

} *id;

局限性:调用一个不存在的方法,编译器会马上报错。

 1 //
 2 //  main.m
 3 //  01-id
 4 //
 5 //  Created by apple on 13-8-8.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Person.h"
11
12
13 void test(id d)
14 {
15
16 }
17
18 int main(int argc, const char * argv[])
19 {
20
21     @autoreleasepool {
22         Person *p = [Person new];
23         //[p fsdfdsfd];
24
25         NSObject *o = [Person new];
26
27
28         // id  == NSObject *
29         // 万能指针,能指向\操作任何OC对象
30         id d = [Person new];
31
32         [d setAge:10];
33
34         [d setObj:@"321423432"];
35
36         NSLog(@"%d", [d age]);
37     }
38     return 0;
39 }

OC语言构造方法

一、构造方法

构造方法的调用

完整的创建一个可用的对象:Person *p=[Person new];

New方法的内部会分别调用两个方法来完成2件事情,1)使用alloc方法来分配存储空间(返回分配的对象);2)使用init方法来对对象进行初始化。

可以把new方法拆开如下:

1.调用类方法+alloc分配存储空间,返回未经初始化的对象

Person *p1=[person  alloc];

2.调用对象方法-init进行初始化,返回对象本身

Person *p2=[p1 init];

3.以上两个过程整合为一句:

Person *p=[[Person alloc] init];

说明:init方法就是构造方法,是用来初始化对象的方法,注意这是一个对象方法,一减号开头。默认初始化完毕后,所有成员变量的值都为0。

  构造方法使用注意

(1)子类拥有的成员变量包括自己的成员变量以及从父类继承而来的成员变量,在重写构造方法的时候应该首先对从父类继承而来的成员变量先进行初始化。

(2)原则:先初始化父类的,再初始化子类的。

(3)重写构造方法的目的:为了让对象方法一创建出来,成员变量就会有一些固定的值。

(4)注意点:#1先调用父类的构造方法[super init]; #2再进行子类内部成员变量的初始化。

二、自定义构造方法

(一)自定义构造方法的规范

(1)一定是对象方法,以减号开头

(2)返回值一般是id类型

(3)方法名一般以initWith开头

(二)自定义构造方法的代码实现

Person类的声明,其中声明了两个接收参数的自定义构造方法

 1 //
 2 //  Person.h
 3 //  03-自定义构造方法
 4 //
 5 //  Created by apple on 13-8-8.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10
11 @interface Person : NSObject
12 @property NSString *name;
13 @property int age;
14
15 /*
16  自定义构造方法的规范
17  1.一定是对象方法,一定以 - 开头
18  2.返回值一般是id类型
19  3.方法名一般以initWith开头
20 */
21
22 - (id)initWithName:(NSString *)name;
23
24 - (id)initWithAge:(int)age;
25
26 // initWithName:andAge:
27 - (id)initWithName:(NSString *)name andAge:(int)age;
28
29 @end

Person类的实现

 1 //
 2 //  Person.m
 3 //  03-自定义构造方法
 4 //
 5 //  Created by apple on 13-8-8.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import "Person.h"
10
11 @implementation Person
12
13 - (id)init
14 {
15     if ( self = [super init] )
16     {
17         _name = @"Jack";
18     }
19     return self;
20 }
21
22 - (id)initWithName:(NSString *)name
23 {
24
25     if ( self = [super init] )
26     {
27         _name = name;
28     }
29
30     return self;
31 }
32
33 - (id)initWithAge:(int)age
34 {
35     if ( self = [super init] )
36     {
37         _age = age;
38     }
39     return self;
40 }
41
42 - (id)initWithName:(NSString *)name andAge:(int)age
43 {
44     if ( self = [super init] )
45     {
46         _name = name;
47         _age = age;
48     }
49     return self;
50 }
51
52 @end

Student继承自Person类,声明了一个接收三个参数的构造方法

 1 //
 2 //  Student.h
 3 //  03-自定义构造方法
 4 //
 5 //  Created by apple on 13-8-8.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import "Person.h"
10
11 @interface Student : Person
12 @property int no;
13
14 - (id)initWithNo:(int)no;
15
16 - (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no;
17
18 @end

Student类的实现

 1 //
 2 //  Student.m
 3 //  03-自定义构造方法
 4 //
 5 //  Created by apple on 13-8-8.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import "Student.h"
10
11 @implementation Student
12 - (id)initWithNo:(int)no
13 {
14     if ( self = [super init] )
15     {
16         _no = no;
17     }
18     return self;
19 }
20
21 // 父类的属性交给父类方法去处理,子类方法处理子类自己的属性
22 - (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
23 {
24     // 将name、age传递到父类方法中进行初始化
25     if ( self = [super initWithName:name andAge:age])
26     {
27         _no = no;
28     }
29
30     return self;
31 }
32
33 //- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
34 //{
35 //     if ( self = [super init] )
36 //     {
37 //         _no  = no;
38 //         //_name = name;
39 //         self.name = name;
40 //         self.age = age;
41 //
42 //         //[self setName:name];
43 //         //[self setAge:age];
44 //     }
45 //
46 //    return self;
47 //}
48 @end

测试主程序

 1 //
 2 //  main.m
 3 //  03-自定义构造方法
 4 //
 5 //  Created by apple on 13-8-8.
 6 //  Copyright (c) 2013年 itcast. All rights reserved.
 7 //
 8
 9 #import <Foundation/Foundation.h>
10 #import "Person.h"
11 #import "Student.h"
12
13 int main(int argc, const char * argv[])
14 {
15
16     @autoreleasepool {
17         Student *p = [[Student alloc] initWithName:@"Jim" andAge:29 andNo:10];
18         NSLog(@"00000");
19     }
20     return 0;
21 }

(三)自定义构造方法的使用注意

(1)自己做自己的事情

(2)父类的方法交给父类的方法来处理,子类的方法处理子类自己独有的属性

时间: 2024-10-12 03:24:40

黑马程序员——OC的特有语法的相关文章

黑马程序员------OC之点语法、成员变量作用域、@property和@synthesize

-----iOS培训.Android培训.Java培训,期待与您交流----- OC之点语法.成员变量作用域.@property和@synthesize 一.点语法 1)点语法基本概念:当我们使用面向对象的封装特性后,将成员变量私有化,采取使用setter方法和getter方法向外面提供成员变量访问方案.那么我们知道,OC的调用方法的方式是很独特的,采用的是 [对象名(类名)  方法名]  的方式 ,那么很多Java.C#程序员就不习惯了,在Java.C#这些主流的面向对象语言中,调用方法的方式

黑马程序员——OC语言基本语法知识(四)

OC也叫面向对象c,在c语言的基础上增加了一层最小的面向对象语法特点: 1.完全兼容C语言 2.可以在OC代码中混入C语言代码,甚至是C++代码,不是任何源文件代码都能写c++代码,要把拓展名改一改才可以写 3.可以在OC开发 Mac OS X平台和IOS平台的应用程序 4..c只能写C语言代码,.m能写OC代码,也能写C语言代码,要写C++代码就要写.MM OC语法预览 1.关键字 基本上所有关键字都是以@开头,少部分不是以@开头 2.字符串以@开头 比如@"HELLO"是OC字符串

黑马程序员----OC的弱语法

OC弱语法 OC在运行过程中才会检测对象有没有实现相应的方法(动态监测),而即使没有写方法的实现代码,在编译.连接过程中只会有警告,运行时会奔溃,如果在手机上运行这样的代码,运行过程中就造成闪退! 1.如果对象调用了一个既没有声明又没有实现的方法test,编译能通过(有警告:warning: 'Person' may not respond to 'test'),但是还是能连接成功,但是运行时会出现下面的经典错误: 经典错误:不能识别消息发送给对象(运行时会监测方法有没有实现),会使程序运行时自

黑马程序员——OC语言基本语法知识(五)

block :用来保存一段代码,用^ 1.block 特点:  1> Block封装了一段代码,可以在任何时候执行   2> Block可以作为函数或者函数的返回值,而其本身又可以带输入参数或返回值  3> 苹果官方建议尽量多用block,在多线程.异步任务.集合遍历.集合排序.动画转场用的很多  4> Block可以在程序运行时凭空产生一个代码保存起来 2.block的标志:^ 3.block跟函数很像  1> 可以保存代码  2> 有返回值  3> 有形参  

黑马程序员——OC语言基本语法知识(二)

一.基本使用 1.内存管理的范围:任何继承了NSObject的对象,对其他基本数据类型(int.char.float.double.struct.enum等)无效 2.对象的基本结构: *每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象 *每个OC对象内部专门有4个字节的存储空间来存储引用计数器 3.引用计数器的作用*当使用alloc.new或者copy创建一个新对象时,新对象的引用计数器默认就是1*当一个对象的引用计数器值为0时,对象占用的

黑马程序员——OC语言基本语法知识(一)

*** 封装 *** 一. set方法 通过 指针->成员变量名 方式给成员变量赋值具有危险性, 可能被赋值为不合理的数值.不允许通过指针直接修改成员变量, 就要去掉@public. 通过方法来修改成员变量的值, 方法中可以加代码保证接收的值是合理的赋值. 设置成员变量属性值的方法, 通常称为该属性的set方法, 命名方式为 setAge: , 接收一个相同类型的参数,形参的名称不能和成员变量名相同. 举例: - (void)setAge:(int)newAge { // 对传进来的参数值进行过

黑马程序员——OC语言基本语法知识foundation

1.结构体:NSRange .NSPoint(CGPoint). NSSize(CGSize). NSRect(CGRect) NSRange :表示范围,有两个成员变量:location ,length 例如:@“I love you”求出love的范围 int main() { NSRange r1= NsMakeRange{2,4}; return 0; } 例如:查找出某个字符串在str中的范围 NSString *str = @"I love you"; NSRanger r

黑马程序员——OC语言基本语法知识(三)

*** 类方法 *** 声明和实现: @interface Person : NSObject + (void) age;  //声明一个类方法 @end @implementation Person + (void) age   //类方法的实现 { NSLog(@"abcd"); } @end int main() { [Person age];  //通过类名调用类方法 return 0; } 类方法比对象方法优化体现在不用创建对象就能执行行为. 在内存中, + 识别为类方法, 

黑马程序员-OC特有语法:分类category,给NSString增加方法计算字符串中数字的个数

1:分类的使用场景:想对一个类,扩充一些功能,而又不改变原来类的模型,也不用继承,这时OC中的特有语法:分类可以做到: 当然分类也是一个类,也需要声明和实现,声明在.h文件中,实现在.m文件中,格式如下 // 声明 @interface  类名  (分类名称) @end // 实现 @implementation 类名 (分类名称) @end 2:分类的好处,当一个类比较庞大时,不同的部分可以放到不同的分类中,也方便团队中类的开发: 3:分类使用注意: a:分类不能增加成员变量,只能对原类增加方