第一个OC类、解析第一个OC程序

时间:2022-06-20 22:35:36
01第一个OC 类
本文目录
• 一、语法简介
• 二、用Xcode创建第一个OC的类
• 三、第一个类的代码解析
• 四、添加成员变量
• 五、添加方法
• 六、跟Java的比较
• 七、创建对象
• 八、访问公共成员变量和方法
说明:这个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>
23@interface Student : NSObject
45@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"23@implementation Student
45@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>
23@interface Student : NSObject {
4int age; // 年龄5}
67@end
 
1> 第4行定义了一个int类型的成员变量age,age的默认作用域是@protected,即可以在Student类内部和子类中访问
2> 成员变量必须写在大括号{ }里面
 
2.设置成员变量的作用域
接下来给Student增加几个不同作用域的成员变量
 
 1#import <Foundation/Foundation.h>
 2 3@interface Student : NSObject {
 4int age; // 年龄 5 6@public 7int no; // 学号 8int score; // 成绩 910@protected11float height; // 身高1213@private14float weight; // 体重15}
1617@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 {
 4int age; // 年龄 5 6@public 7int no; // 学号 8int score; // 成绩 910@protected11float height; // 身高1213@private14float weight; // 体重15}
1617// age的get方法18 - (int)age;
1920// age的set方法21 - (void)setAge:(int)newAge;
2223@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 8return age;
 9}
1011// age的set方法12 - (void)setAge:(int)newAge {
13// 将参数newAge赋值给成员变量age14    age = newAge;
15}
1617// 同时设置age和height18 - (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文件就可以搞定成员变量和方法
 
 1publicclass Student {
 2protectedint age;
 3protectedfloat height;
 4 5publicint no;
 6publicint score;
 7 8privatefloat weight;
 910/**11    * age的get方法
12*/13publicint getAge() {
14return age;
15    }
1617/**18    * age的set方法
19*/20publicvoid setAge(int newAge) {
21        age = newAge;
22    }
2324/**25    * 同时设置age和height
26*/27publicvoid 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 4int main(int argc, constchar * argv[])
 5{
 6    @autoreleasepool {
 7        Student *stu = [[Student alloc] init];
 8 9        [stu release];
10    }
11return0;
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];
23 [stu release];
不过我们还是习惯使用alloc和init来创建对象
2> 前面我们调用了Student的alloc、init、new方法,但是你会发现Student.h中并没有声明这些方法,为什么能够调用呢?原因很简单,这些方法都是父类NSObject的,子类当然可以调用父类的方法。
 
回到顶部
八、访问公共成员变量和方法
前面已经成功创建了一个Student对象,接下来访问一下它的公共变量和方法。
 
 1#import <Foundation/Foundation.h>
 2#import"Student.h" 3 4int main(int argc, constchar * argv[])
 5{
 6    @autoreleasepool {
 7        Student *stu = [[Student alloc] init];
 8 9// 访问公共变量no10        stu->no = 10;
1112// 调用setAge:方法设置变量age的值13        [stu setAge:27];
1415// 调用setAge:andHeight:方法同时设置变量age和height的值16        [stu setAge:28 andHeight:1.88f];
1718// 访问公共变量no19int no = stu->no;
20// 调用age方法获取变量age的值21int age = [stu age];
2223// 打印no和age的值24        NSLog(@"no is %i and age is %i", no, age);
2526        [stu release];
27    }
28return0;
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-0621:54:56.221 第一个OC程序[1276:303] no is10 and age is28
 
02解析第一个OC程序.note
 
新建了第一个OC程序,这讲就来解析它内部的代码。
查看项目结构可以发现这个程序中只有一个源文件:main.m
 第一个OC类、解析第一个OC程序
打开main.m文件,代码如下
 
 1#import <Foundation/Foundation.h>
 2 3int main(int argc, constchar * argv[])
 4{
 5 6    @autoreleasepool {
 7 8// insert code here... 9        NSLog(@"Hello, World!");
1011    }
12return0;
13 }
 
1.程序的入口点:main函数
跟C程序一样,OC程序的入口点依然是main函数。在main.m的第3行已定义了一个main函数。
 
2.@autoreleasepool
在Java中,有垃圾回收机制,系统会自动回收不再使用的对象;而OC是不支持垃圾回收的,需要开发人员编写代码来释放对象所占用的内存。在第6行有个@autoreleasepool{},这是跟内存管理有关的,暂时不用理解它的意思,你只需要记住:以后的OC代码都写在@autoreleasepool的{}内部。
 
3.NSLog
1> 第9行的NSLog是一个日志输出函数,它可以将传入的OC字符串参数输出到控制台上。
2> 函数参数@"Hello, Wolrd!"是一个OC字符串,并不是C语言字符串,所有OC字符串的前面都有个@。
3> 第9行代码NSLog(@"Hello, World!");的输出结果是:
 
红框左边的信息是NSLog自动加上去的,比如日志输出时间、项目名称等。而且NSLog输出完毕后自动换行。
4> NSLog也可以像C语言的printf函数一样支持格式符
1int age = 10;
2 NSLog(@"My age is %i and height is %.2f", age, 1.55f);
* %i表示接收整型数据
* %f表示接收浮点型数据,%.2f表示保留2位小数
* 输出结果:
2013-04-0617:43:07.380 第一个OC程序[693:303] My age is10 and height is1.55
 
4.#import
1> #import是一个预处理指令,作用跟C语言的#include类似,都是 包含(拷贝)某个文件的内容 到 预处理指令所在的位置。
2> 第1行的#import <Foundation/Foundation.h>表示包含Foundation框架中的Foundation.h文件。
1) Foundation框架中包含了很多常用的类和函数,比如字符串处理类NSString、日志输出函数NSLog。它的重要程度相当于Java中的java.lang.*
2) Foundation框架和Foundation.h文件的位置:
 第一个OC类、解析第一个OC程序
3> 我在C语言专题第三讲说过:.h称为头文件,一般用来声明一些函数,想要使用这些函数,就必须用#include包含函数所在的头文件。我们在第9行中使用的NSLog函数存在于Foundation.h文件中,因此要先包含Foundation.h文件才能使用NSLog函数。就好像在Java中,你用import关键字引入一个类后才能正常使用这个类。
4> 在C\C++中,我们用#include来包含头文件,缺点就是同一个头文件可能被包含多次。为了解决这个问题,一般会这样写头文件:
#ifndef _TEST_H_
#define _TEST_H_

/*.....*/#endif
我们在OC中,就使用#import来包含头文件,优点是可以自动防止同一个头文件被包含多次。

5> #import <...>表示包含系统自带的文件,#import "..."表示包含开发人员自己创建的文件

第一个OC类、解析第一个OC程序的更多相关文章

  1. java定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea&lpar;&rpar;方法返回圆的面积

    需求如下:(1)定义一个Circle类,包含一个double型的radius属性代表圆的半径,一个findArea()方法返回圆的面积. (2)定义一个类PassObject,在类中定义一个方法pri ...

  2. Objective-c 总结(一):OC类的设计

    (一)学习目标: 1.面向对象基本概念: OOP的主要思想是把构成问题的各个事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述一个事物在整个解决问题步骤中的行为. 2.熟悉OC类的定 ...

  3. 将Bean转换为Json形式的一个工具类

    这边遇到一个问题:  1.做一个bean类,实现一个函数,能够把bean生成json字符串.按字段作为key,字段值作为value的方式生成,并且按key的ascii码的升序生成.     2.提示: ...

  4. 使用代码向一个普通的类注入Spring的实例

    转载请在页首注明作者与原文地址 一:应用场景 什么是普通的类,就是没有@Controller,@Service,@Repository,@Component等注解修饰的类,同时xml文件中,也没有相应 ...

  5. 怎样从一个DLL中导出一个C&plus;&plus;类

    原文作者:Alex Blekhman    翻译:朱金灿 原文来源: http://www.codeproject.com/KB/cpp/howto_export_cpp_classes.aspx 译 ...

  6. 分享一个SqliteHelper类

    分享一个SqliteHelper类 SQLite作为一个本地文件数据库相当好用,小巧.快速.支持事务.关系型,甚至可以运行在Android上.在很久以前的一个项目中,我们用过它来将接收到的数据做本地统 ...

  7. 04:第一个OC类

    1.类与对象的关系 面向对象的核心就是对象,那怎么创建对象? OC中创建对象比较复杂, 首先要理解一个概念叫做类. 现实生活中是根据一份描述,一份模板创建对象,编程语言也一样,也必须先有一份描述,在这 ...

  8. OC学习那些事:第一个OC类

    一.创建一个新的OC类: 1.点击File->New File,打开Choose a template for your new file窗口,选择Objective-C class,点击Nex ...

  9. 第一个OC类

    1.如何声明一个类 格式 注意: 1.必须以@interface开头,@end结尾 2.成员变量的声明,必须写在@interface与@end之间的大括号中 3.方法的声明必须在{}下面,不能写在{} ...

随机推荐

  1. ASP&period;NET MVC5学习笔记01

    由于之前在项目中也使用MVC进行开发,但是具体是那个版本就不是很清楚了,但是我觉得大体的思想是相同的,只是版本高的在版本低的基础上增加了一些更加方便操作的东西.下面是我学习ASP.NET MVC5高级 ...

  2. java&period;lang&period;NoSuchMethodError&colon;

    Servlet.service() for servlet [springMVC] in context with path [/mobile] threw exception [Handler pr ...

  3. Delphi写的DLL回调C&num;

    C#的调用Delphi的DLL没有问题,DLL回调时遇到了麻烦,网上找了个方法,解决了这个问题 Delphi部分,列举了三种回调函数定义 library test; uses SysUtils; {$ ...

  4. winfrom中按钮文本&amp&semi;的显示问题&sol;按钮快捷键设置问题

    其实这个问题是因为“&”有特殊的意义-就是可以作为快捷键 第一种:Alt + *(按钮快捷键) 在大家给button.label.menuStrip等控件设置Text属性时在名字后边加&amp ...

  5. CSS3 Gradient-CSS3渐变

    CSS3 Gradient分为linear-gradient(线性渐变)和radial-gradient(径向渐变).而我们今天主要是针对线性渐变来剖析其具体的用法.为了更好的应用CSS3 Gradi ...

  6. postgresql 基本使用及常见问题

    基本使用参考 https://www.yiibai.com/postgresql/postgresql-insert.html 关于编码问题: 这是一个很复杂,但弄懂之后还是很迷的问题. postgr ...

  7. windows服务安装,卸载

    首先管理员身份进入cmd cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ 进入C:\Windows\Microsoft.NET\Framewor ...

  8. 用python来自动玩类似跳一跳的小游戏

    最近春节,qq上出了一个叫穿越福城的小游戏.游戏的玩法类似挑一挑,也是通过一个个木桩.只不过把跳的过程变成了搭*.按的时间越长,*越长.*过长或者过短小企鹅都会掉下去,游戏失败.我的目的是用py ...

  9. 【AI】Computing Machinery and Intelligence - 计算机器与智能

    [论文标题] Computing Machinery and Intelligence (1950) [论文作者] A. M. Turing (Alan Mathison Turing) [论文链接] ...

  10. drizzleDumper的原理分析和使用说明

    https://blog.csdn.net/qq1084283172/article/details/53561622 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...