转自:http://www.cnblogs.com/heyonggang/p/3441051.html

来源:http://www.cnblogs.com/mjios/archive/2013/04/06/3002814.html

说明:这个Objective-C专题,是学习iOS开发的前奏,也为了让有面向对象语言开发经验的程序员,能够快速上手Objective-C。如果你还没有编程经验,或者对Objective-C、iOS开发不感兴趣,请忽略。学习本专题之前,建议先学习C语言专题。

OC是一门面向对象的语言,因此它也有类、对象、静态\动态方法、成员变量的概念。这讲就来创建第一个OC的类。

一、语法简介

1.类

在Java中,我们用1个.java文件就可以描述清楚一个类;在OC中,一般用2个文件来描述一个类:

1> .h:类的声明文件,用于声明成员变量、方法。类的声明使用关键字@interface和@end。

注意:.h中的方法只是做一个声明,并不对方法进行实现。也就是说,只是说明一下方法名、方法的返回值类型、方法接收的参数类型而已,并不会编写方法内部的代码。

2> .m:类的实现文件,用于实现.h中声明的方法。类的实现使用关键字@implementation和@end。

2.方法

1>
方法的声明和实现,都必须以 + 或者 - 开头

  • + 表示类方法(静态方法)
  • - 表示对象方法(动态方法)

2> 在.h中声明的所有方法作用域都是public类型,不能更改

3.成员变量

成员变量的常用作用域有3种:

1>
@public 全局都可以访问
2> @protected 只能在类内部和子类中访问
3> @private 只能在类内部访问

比Java少了一种作用域:包权限作用域,原因很明显:OC没有包名的概念。

二、用Xcode创建第一个OC的类

1.右击项目文件夹或者文件,选择"New File"

2.选择Cocoa的"Objective-C class"

3.输入类名和选择父类

这里的类名为Student,父类是NSobject

4.创建完毕后,项目中多了两个文件

* Student.h是类的声明文件,Student.m是类的实现文件

* 默认情况下,这2个文件的文件名跟类名一致

* 编译器只会编译.m文件,并不会编译.h文件

三、第一个类的代码解析

1.Student.h - 类的声明文件

1 #import <Foundation/Foundation.h>
2
3 @interface Student : NSObject
4
5 @end

1> 看第3行,OC中使用关键字@interface来声明一个类,@interface后面紧跟着类名Student。

2> 类名Student后面的冒号":"表示继承,即第3行代码的意思是Student继承自NSObject。

3> 因为NSObject被声明在Foundation.h中,所以在第1行用#import包含了Foundation.h文件。

4> 第5行的@end表示类的声明结束了。@interface和@end是配套使用的。

2.Student.m - 类的实现文件

1 #import "Student.h"
2
3 @implementation Student
4
5 @end

1> 看第3行,OC中使用关键字@implementation来实现一个类。@implementation后面紧跟的类名,表示究竟要实现哪一个类。

2> 因为Student这个类是声明在Student.h中的,所以在第1行用#import包含了Student.h文件。如果你不包含Student.h,第3行代码肯定报错,因为它根本不知道Student是个什么鬼东西。

3> 第5行的@end表示类的实现结束了。@implementation和@end是配套使用的。

四、添加成员变量

正常情况下,我们都是把成员变量定义在头文件中,也就是类的声明文件(.h)中

1.给Student添加一个成员变量

1 #import <Foundation/Foundation.h>
2
3 @interface Student : NSObject {
4 int age; // 年龄
5 }
6
7 @end

1> 第4行定义了一个int类型的成员变量age,age的默认作用域是@protected,即可以在Student类内部和子类中访问

2> 成员变量必须写在大括号{ }里面

2.设置成员变量的作用域

接下来给Student增加几个不同作用域的成员变量

 1 #import <Foundation/Foundation.h>
2
3 @interface Student : NSObject {
4 int age; // 年龄
5
6 @public
7 int no; // 学号
8 int score; // 成绩
9
10 @protected
11 float height; // 身高
12
13 @private
14 float weight; // 体重
15 }
16
17 @end

一共有5个成员变量,其中

@public作用域的有:no、score

@protected作用域的有:age、height

@private作用域的有:weight

五、添加方法

前面我们定义了一个成员变量age,它的作用域是@protected,外界不能直接访问它。为了保证面向对象数据的封装性,我们可以提供age的get方法和set方法,让外界间接访问age。接下来在Student中添加age的get方法和set方法。

1.在Student.h中声明方法

 1 #import <Foundation/Foundation.h>
2
3 @interface Student : NSObject {
4 int age; // 年龄
5
6 @public
7 int no; // 学号
8 int score; // 成绩
9
10 @protected
11 float height; // 身高
12
13 @private
14 float weight; // 体重
15 }
16
17 // age的get方法
18 - (int)age;
19
20 // age的set方法
21 - (void)setAge:(int)newAge;
22
23 @end

1> 第18行声明了age的get方法,方法名就叫做age,OC建议get方法的名字跟成员变量保持一致(如果是在Java中,就应该叫做getAge)

2> 第18行最面的 - 表示这是一个动态方法( + 则表示静态方法)。age前面的(int)表示方法的返回值为int类型,方法的返回值和参数类型都需要用小括号()包住

3> 第21行声明了age的set方法,前面的 - 表示动态方法,(void)表示方法没有返回值

4> 在OC方法中,一个冒号:对应一个参数。由于第21行age的set方法接收一个int类型的参数,参数名为newAge,所以(int)newAge前面有一个冒号:

5> 一定要记住:一个冒号:对应一个参数,而且冒号:也是方法名的一部分。因此第21行set方法的方法名是setAge:,而不是setAge

再加大一下难度,假如增加一个方法可以同时设置age和height,那么就应该这样写:

1 - (void)setAge:(int)newAge andHeight:(float)newHeight;

* 这个方法是动态方法、没有返回值,接收2个参数,所以有2个冒号:

* 这个方法的方法名是setAge:andHeight:

* 其实andHeight是可以省略的,它只是为了让方法名念起来通顺一点,也让(float)newHeight前面的冒号:不那么孤单

2.在Student.m中实现方法

前面已经在Student.h中声明了3个方法,接下来一一实现它们

 1 #import "Student.h"
2
3 @implementation Student
4
5 // age的get方法
6 - (int)age {
7 // 直接返回成员变量age
8 return age;
9 }
10
11 // age的set方法
12 - (void)setAge:(int)newAge {
13 // 将参数newAge赋值给成员变量age
14 age = newAge;
15 }
16
17 // 同时设置age和height
18 - (void)setAge:(int)newAge andHeight:(float)newHeight {
19 age = newAge;
20 height = newHeight;
21 }
22 @end

第6行对age方法进行了实现,第12行对setAge:方法进行了实现,第18行对setAge:andHeight:方法进行了实现

六、跟Java的比较

如果是在Java中,一个Student.java文件就可以搞定成员变量和方法

 1 public class Student {
2 protected int age;
3 protected float height;
4
5 public int no;
6 public int score;
7
8 private float weight;
9
10 /**
11 * age的get方法
12 */
13 public int getAge() {
14 return age;
15 }
16
17 /**
18 * age的set方法
19 */
20 public void setAge(int newAge) {
21 age = newAge;
22 }
23
24 /**
25 * 同时设置age和height
26 */
27 public void setAgeAndHeight(int newAge, float newHeight) {
28 age = newAge;
29 height = newHeight;
30 }
31 }

七、创建对象

前面已经定义了一个Student类,成员变量和方法都有了,接下来看一下怎么使用这个类创建对象。

由于OC程序的入口点是main函数,所以在main.m文件中演示Student类的使用。

先上完整代码

 1 #import <Foundation/Foundation.h>
2 #import "Student.h"
3
4 int main(int argc, const char * argv[])
5 {
6 @autoreleasepool {
7 Student *stu = [[Student alloc] init];
8
9 [stu release];
10 }
11 return 0;
12 }

1.包含Student.h

因为要用到Student这个类,所以在第2行包含了它的头文件

#import "Student.h"

2.创建对象

1> 在Java中是使用关键字new来创建对象,比如new Student(),其实这句代码做了2件事:

  • 给对象分配存储空间
  • 调用Student的构造方法进行初始化

2> 在OC中创建对象也需要按顺序做上面所述的2件事

1)调用Student类的静态方法alloc分配存储空间

Student *stu = [Student alloc];
  • OC是方法调用是用中括号[ ],方法调用者写在括号左侧,方法名写在括号右侧,中间留点空格。因此上面是调用了Student类的静态方法alloc。
  • 上面调用的alloc方法会返回分配好内存的Student对象,在等号左边用了一个指向Student类型的指针变量stu来接收这个对象,注意stu左边的*号。所有OC对象都是用指针变量来接收的,如果你不了解指针,你记住下面这点就行了:利用类名定义一个变量时,类名后面一定要带个*号。
  • alloc方法是这样声明的:
+ (id)alloc;

可以看到,它的返回值类型是id,这个id代表任何指针类型,你可以暂时理解为:id可以代表任何OC对象,类似于NSObject *。

2)调用Student对象的构造方法init进行初始化

前面调用alloc方法返回的Student对象stu是不能正常使用的,因为仅仅是分配了内存,并没有进行初始化,接下来调用对象的init方法进行初始化

stu = [stu init];

看清楚了,由于init是动态方法,所以这里使用stu变量来调用,并不是使用类名来调用。init会返回已经初始化完毕的对象,再次赋值给了stu变量。这时候的Student对象stu才能正常使用。

3)其实,我们最常见的做法是将alloc和init连起来使用:

Student *stu = [[Student alloc] init];

相信有面向对象开发经验的你一眼就能看懂了,在main.m完整代码的第7行。

3.销毁对象

由于OC不支持垃圾回收,因此当不再使用某个对象时,需要调用对象的release方法释放此对象。我们在第9行销毁了stu对象。

[stu release];

这个release方法在这里调用一次即可,不要觉得多调用多几次,对象就会释放地干净一点,这样做会很危险,容易造成野指针错误。

4.其他

1> 也可以调用静态方法new快速创建一个对象

1 Student *stu = [Student new];
2
3 [stu release];

不过我们还是习惯使用alloc和init来创建对象

2> 前面我们调用了Student的alloc、init、new方法,但是你会发现Student.h中并没有声明这些方法,为什么能够调用呢?原因很简单,这些方法都是父类NSObject的,子类当然可以调用父类的方法。

八、访问公共成员变量和方法

前面已经成功创建了一个Student对象,接下来访问一下它的公共变量和方法。

 1 #import <Foundation/Foundation.h>
2 #import "Student.h"
3
4 int main(int argc, const char * argv[])
5 {
6 @autoreleasepool {
7 Student *stu = [[Student alloc] init];
8
9 // 访问公共变量no
10 stu->no = 10;
11
12 // 调用setAge:方法设置变量age的值
13 [stu setAge:27];
14
15 // 调用setAge:andHeight:方法同时设置变量age和height的值
16 [stu setAge:28 andHeight:1.88f];
17
18 // 访问公共变量no
19 int no = stu->no;
20 // 调用age方法获取变量age的值
21 int age = [stu age];
22
23 // 打印no和age的值
24 NSLog(@"no is %i and age is %i", no, age);
25
26 [stu release];
27 }
28 return 0;
29 }

1.第7行创建了Student对象,第26行销毁了对象

2.第10行和第19行访问了Student对象的公共成员变量no,如果不是公共变量,不能像这样直接访问。注意访问方式:对象->成员变量

3.第13行调用了Student对象的setAge:方法,传入参数27修改了成员变量age的值

4.第16行调用了Student对象的setAge:andHeight:方法,同时修改了成员变量age和height的值

5.第21行调用了Student对象的age方法获取成员变量age的值

6.第24行输出了age和no的值,输出结果:

2013-04-06 21:54:56.221 第一个OC程序[1276:303] no is 10 and age is 28

第一个Object-C类的更多相关文章

  1. JAVA 一个特殊的类 Object

    一个特殊的类Object:它是java中所有对象的直接或间接父类,根父类(基类),它里面定义的功能是所有对象都应该具备的(所有的类,都是继承这个类的) 记住:当定义一个新类时,没有指明要继承某类,它默 ...

  2. JAVA中有一个特殊的类: Object

    JAVA中有一个特殊的类: Object.它是JAVA体系中所有类的父类(直接父类或者间接父类). 此类中的方法可以使所的类均继承. 以下介绍的三种方法属于Object: (1) finalize方法 ...

  3. c# 把一个匿名对象赋值给一个Object类型的变量后,怎么取这个变量? c# dynamic动态类型和匿名类 详解C# 匿名对象(匿名类型)、var、动态类型 dynamic 深入浅析C#中的var和dynamic

    比如有一个匿名对象,var  result =......Select( a=>new {  id=a.id, name=a.name});然后Object  obj =  result ;我怎 ...

  4. Object对象类

    Object对象类是所有类的祖先,他是默认自动继承的 Java为什么要做一个对象类呢?对象类的目的就是归一了类型,他就是把所有的类所有的对象归纳成为 Object类型.因为对象他认为对象应该拥有一些什 ...

  5. new一个Object对象占用多少内存?

    Java的自动内存管理机制省却了很多编码工作,大大地提高了Java的生产力,而且JVM的性能也越来越好,特别是G1的出现,改善了垃圾回收中stop the world的状况. 也许很多人都没有考虑过这 ...

  6. 我写的一个ExcelHelper通用类,可用于读取或生成数据

    读取或生成EXCEL数据的方法有很多,一般常见的有: 1.通过OFFICE EXCEL组件,优点:读取与生成EXCEL文件方便,缺点:服务器上必须安装OFFICE软件,且进程无法及时释放 2.通过第三 ...

  7. Spring自定义一个拦截器类SomeInterceptor,实现HandlerInterceptor接口及其方法的实例

    利用Spring的拦截器可以在处理器Controller方法执行前和后增加逻辑代码,了解拦截器中preHandle.postHandle和afterCompletion方法执行时机. 自定义一个拦截器 ...

  8. object C—类中函数的调用

    Object C-类中函数的调用 创建,三个类.然后,在代码中调用相同名字的函数.观察他们的调用次序. @interface test : NSObject - (void)print; @end @ ...

  9. C# System.Object基类

    System.Object 基类 System.Object在.Net中是所有类型的基类,任何类型都直接或间接地继承自System.Object.没有指定基类的类型都默认继承于System.Objec ...

  10. [转]new一个Object对象占用多少内存?

    我们分解下ArrayList arr = new ArrayList();等同于ArrayList arr = null;//初始化arr = new ArrayList();//实例化这两个过程.初 ...

随机推荐

  1. MySQL、PostgreSQL、Ingres r3、MaxDB等开源数据库的详细比较

    1.MySQL 5 作为当今最流行的开放源码数据库之一,MySQL数据库为用户提供了一个相对简单的 解决方案,适用于广泛的应用程序部署,能够降低用户的TCO.MySQL是一个多线程.结构化查询语言(S ...

  2. adb使用

    一.使用adb删除系统应用,如Launcher.apk adb root                 获取root权限 adb remount          挂载系统的读写权限 adb she ...

  3. HBase - Phoenix剖析

    1.概述 在<Hadoop-Drill深度剖析>一文当中,给大家介绍了Drill的相关内容,就实时查询来说,Drill基本能够满足要求,同时还可以做一个简单业务上的聚合,如果在使用Hive ...

  4. 日常工作中的点滴总结from 2014-03

    一 关于 写方案: 写某个产品的方案基本应包括以下几点: 1产品目前现状(国内外)  2产品意义.作用 3产品架构 4产品优势 5产品功能讲解 二 关于 处理下属工作方向不正确的事务 首先 先肯定 下 ...

  5. WeifenLuo组件中如何设置停靠窗体的宽度

    在项目中使用了WeifenLuo.WinFormsUI.Docking组件,窗体停靠效果非常棒. 现在项目出现了这样的需求,希望可以控制停靠窗体的宽度,因为默认的宽度往往会造成停靠窗体的内容显示不完全 ...

  6. phalcon开发工具(phalcon-devtools)

    一.简介 Phalcon提供的这个开发工具主要是用来辅助开发,比如生成一些程序的基本框架,生成控制器模型等.使用这个工具我们只需要一个简单的命令即可生成应用的基本框架. 二.下载 github: ht ...

  7. win7中安装redis

    1.下载redis安装版本 https://github.com/rgl/redis/downloads 2.设置环境变量 将redies的安装目录设置为环境变量 参考: http://www.cnb ...

  8. 纯CSS3实现3D特效的iPhone 6动画

    iPhone 6发布不久,屌丝怎能买得起,不过作为程序员,今天看到一个用纯CSS3绘制的iPhone 6,由于CSS3特性的运用,带有点3D的动画特效,大家可以先来看看在线演示效果. 在线演示    ...

  9. QImage 图像格式小结

    原地址:http://tracey2076.blog.51cto.com/1623739/539690 嗯,这个QImage的问题研究好久了,有段时间没用,忘了,已经被两次问到了,突然有点解释不清楚, ...

  10. FFmpeg编译出错_img_convert 找不到

    问题出现在下载的ffmpeg的版本不一样,在0.4.8以前的版本中还有img_convert这个函数,新版本中用sws_getContext和sws_scale代替了.简单说明如下: 新版本的ffmp ...