赞
踩
c语言是面向过程语言,oc则是面向对象是语言,这两者之间究竟有什么区别呢?
面向过程的语言:主要是用于单片机,嵌入式的开发,因为这些编程需要实例化,对内存等资源开销较大,性能是其判断优劣最重要的因素,其缺点就是:相对于面向对象语言来说,较难维护,且不易扩用和扩展
面向对象的语言:易于维护,复用和扩展,由于面向对象语言所用的三个特点,分装,继承和多态,会比较容易写出低耦合,高复用的程序,使得系统更加灵活,易于维护。当然与面向过程的语言比起来,性能会较低。
举个例子吧,如果说面向过程是一份蛋炒饭的话,那么面向对象则更像一份盖浇饭,怎么理解呢?
对于蛋炒饭来说,饭中的每一种配料——即为功能,都非常均匀的融合在了一起,他的突出特点就是香——即性能一般来说高于盖浇饭,但是如果不想要蛋炒饭的某种东西,比如香菜,那么你只能将整份饭重做一遍。
对于盖浇饭来说呢,就是将浇盖的内容和饭分别准备好,如果你不喜欢吃香菜,那我们只需要做一份去掉香菜的盖浇内容,饭和菜之间的耦合度很低,相对的可维护性就较好,对于盖浇饭能够任意的根据需求组合出任意的搭配。
oc相对于c语言:
**oc程序的后缀:**oc文件的后缀名为.m,m代表oc中的一个重要机制message
机制
作为oc中特有的预处理指令,它其实就是#include的升级版:
框架:将在一些开发程序的过程中,把事先需要使用的功能写好,把这些功能分装在类或者函数之中。框架即为类与函数的集合,类比为c语言的函数库。
只要#import <Foundation/Foundation.h> ,就可以使用foundation框架的内容
NSLog
函数是增强版的printf
函数
NSLog(@"输出的内容");
其优点相对于printf
来说有以下几点:
注:NSLog函数的第一个参数为oc字符串,实参的第一个必须以@开头
oc设计了一个更适合存储字符串的类型,专门用来存储oc字符串的地址。
"String"是c语言的字符串,@"string"是一个oc的字符串,其区别就在与字符串前的@
所以NSString就是只能用于存储oc字符串的地址
NSString *s = @"string"
如果在NSLog函数中想打印出NSString类型的字符串,占位符为%@
支持c语言中的数据类型
oc特有的数据类型bool
boolean
class类型:
id类型:
对于面向对象语言来说,最大的特点就是类与对象。
对于类来说,就是某一批对象的抽象集合体;对象则是具体存在的实体。
举个例子:鹿中有许多不同的品种梅花鹿,麋鹿等等……但是他们都可以被抽象归类为鹿。那么不同的鹿品种就相当于对象,而鹿的总称就为类。
类的本质可以被理解为,自定义的一种数据类型,是在内存开辟空间的模版。
在OC中类的定义一共包括两部分:
在上图中我们可以看到,@interface
用于声明定义的接口部分,@end
说明结束声明。
一般来说,我们会将定义类的声明放在.h文件当中,以方便程序的维护。
以下是一个简单的类的实现:
//student.h中的内容
#import <Foundation/Foundation.h>
//Student为类名, NSObject为对象名
@interface Student: NSObject {
//成员名应被定义在大括号之中,且成员名前缀应该有_
int _age;
int _nums
}
- (int)age; //返回值为int的get方法
- (void)setAge:(int)newage; //set方法,一个冒号对应一个参数,没有冒号说明不用传参
- (void)setAge:(int)newage andNums:(int)newnum;//如果我们需要写一个能够获得两个变量的 get 方法
@end
-
代表为动态方法,也称实例方法,必须对象才能够进行调用
+
代表为静态方法,也称类方法,直接用类名就可以进行调用
类的属性不能不能在声明里赋值。
在我们创建类的时候如果包含了其他类的对象,我们其实创建的是该被包含对象的指针变量,而没有生成对象
类中方法的命名也有其相应的规则:
该注意的是,在方法声明当中,所有的类型(包括void
)都需要用圆括号扩起来。并且类的接口部分只是声明方法,并没有为类的实现提供方法体,因此在声明方法之后,应该添加一个分号,代表着声明结束。
//student.m的内容 #import "student.h" @implementation Student - (int)age { return age; } - (void)setAge:(int)newage { _age = newage; } - (void)setAge:(int)newage andNums:(int)newnum { _age = newage; _num = newnum; } @end
@implementation
为类实现的开头,而@end
同样为类实现的结尾
关于类实现部分的语法说明如下:
类实现部分的类名必须与类接口部分的类名相同,用于表示这是同一个类的接口部分和实现部分。类名必须大写。
类实现部分也可声明自己的成员变量,但这些成员变量只能在当前类内访问。因此,在类实现部分声明成员变量相当于定义隐藏的成员变量。
类实现部分必须为类声明部分的每个方法提供方法定义。方法定义由方法签名和方法体组成:实现部分除了实现类接口部分定义的方法之外,也可提供额外的方法定义——这些没有在接口部分定义,只是在实现部分定义的方法,将只能在类实现部分使用。
方法体里多条可执行性语句之间有严格的执行顺序,排在方法体前面的语句总是先执行,排在方法体后面的语句总是后执行。
当程序在运行的期间,某一个类被第一次访问到的时候,会讲这个类存储值内存中代码区,此过程就被称为类加载,当此类被加入到代码区之后,直至程序结束才会被释放。
在.h文件中的所有方法都为公共方法
//main.m中创建变量
#import <Foundation/Foundation.h>
#import "student.m"
int main(int argc, const char* argv[]) {
@autoreleasepool {
Student* stu = [Student alloc];
stu = [stu init];
[stu release];//对象只能释放一次
}
}
分配内存为静态方法alloc
或者new
,创建对象的语法格式为:[类名 + 方法名]
[Student alloc]
,对象之中还有一个指针,在创建时会指向该对象所属的类在代码段中的地址,称之为isa
,相同类的对象该指针指向相同。
[Student new]
(这种方法比较少用)
调用动态方法 init
为对该对象进行初始化:
Student* stu = [Student alloc];
stu = [stu init];
两个可以写为一个
Student* stu = [[Student alloc] init];//定义变量的同时,为变量赋值
[stu release] //对象释放
alloc
和init
方法可以被直接调用,因为其都属于父类NSObject
的方法
在主函数里面调用类的方法
#import <Foundation/Foundation.h>
#import "student.m"
int main(int argc, const char* argv[]) {
@autoreleasepool {
Student* stu = [[Student alloc] init];
[stu setAge : 100];
int age = [stu age];
[stu setAge: 10 andNums: 10];
[stu release];//对象只能释放一次
}
}
oc如同其他面向对象的语言一样,在类与对象之中,存在关键字self
,指向该方法的调用者,当我们需要在实现过程中调用当前类中的方法时就可以使用self
来给我们的程序赋值。在我们先前的实现中,我们刻意避开set
方法中传入变量的名称与我们类中的名称不相同,那如果相同就需要self语法来进行set
方法的操作。
//student.m的内容 #import "student.m" @implementation Student - (int)age { return age; } - (void)setAge:(int)_age { self-> _age = _qge; } - (void)setAge:(int)_age andNums:(int)_num { self-> _age = -age; self-> _num = _num; } @end
或者说如果在一个方法中需要调用到该类的另一个方法,那么也是使用self
#import "FKDog.h"
@implementation FKDog
1/ 实现一个jump 方法
- (void) jump
{
NSLog (@"正 在 执 行 jump 方 法 " );
}
// 实现一个run方法,run方法需要借助jump方法
- (void) run {
[self jump]:
NSLog(@"正在执行run 方法");
}
@end
注:一般来说对象的属性是不能被直接访问的,如果不使用相应方法,允许对象属性可以被外界访问,这需要在声明属性时添加@public关键字。访问的方式为:对象名->属性名 = 值;
id
可以理解为任何对象,有点像c++中的auto
类型,系统的在运行的时候会实行动态绑定,在运行的时候判断其对象所属于的类。
//main.m中创建变量
#import <Foundation/Foundation.h>
#import "student.m"
int main(int argc, const char* argv[]) {
@autoreleasepool {
id stu = [[Student alloc] init];
}
}
Objective-C的方 法不能独立存在 ,所有的方法都必须定义在类里。方法在逻辑上要么属于类,要么属于对象。我们必须创建对象才可以调用方法。
方法的命名规则:
xxxWith
,使得程序就像一个语句一样,拥有主谓宾,提高程序可读性。xxxWith
:(int) and:(int)在方法中,使用+
标识符则说明该方法属于这个类,-
标识符则说明这个方法是该类的实例。
类的声明和实现必须要有,就算没有方法,类的实现也是必不可少的。在特殊情况下,可以只有实现,没有声明。
当对象作为方法的参数的时候,参数类型为类指针。
为了在程序中获取个数可变的形参,需要使用如下关键字 。
va_list:这是一个类型,用于定义指向可变参数列表的指针变量。
va_start:这是一个函数,该函数指定开始处理可变形参的列表,并让指针变量指向可 变形参列表的第一个参数。
va_end:结束处理可变形参,释放指针变量。
•
va_arg : 该 函 数 返 回 获 取 指 针 当 前 指 向 的 参 数 的 值 , 并 将 指 针 移 动 到 指 向 下 一个 参 数 。
下 面 的 实 现 类 对 上 面 的 t e s t :方 法 提 供 了 实 现 。
#import "VarArgs.h" @implementation VarArgs - (void) test:(NSString *) name,...{ // 使用va_1ist 定义一个argList 指针变量,该指针变量指向可变参数列表 va_list argList; // 如果第一个name 参数存在,才需要处理后面的参数 if (name) { // 由于name参数并不在可变参数列表中,因此先处理name参数 NSLog (@"&®" , name) ; // 让arglist指向第一个可变参数列表的第一个参数,开始提取可变参数列表的参数 va_start (arglist, name) ; // va_arg用于提取argList指针当前指向的参数,并将指针移动到指向下一个参数 //arg变量用于保存当前获取的参数,如果该参数不为ni1,则进入循环体 NSString* arg = va_arg (arglist, id) ; while (arg) { // 打 印 出 每 一个 参 数 NSLog(@"%@" ,arg): arg = va_arg (argList, id) ; // 再次提取下一个参数,并将指针移动到指向下一个参数 } } // 释放argList指针,结束提取 va_end (argList); }
当一个指针为nil
的时候,通过这一个指针去调用该对象的方法,运行不会报错,只是不会运行此方法。
有些时候我们在程序只需要存在一个类的对象,频繁的创建只会使得系统性能下降,比如:系统只有一个系统管理器,,一个打印设备……
如果一个类始终在程序中只能创建一个实例,那么我们则称这个类为单例类。
单例类可以通过全局变量声明static
来实现,我们在实现方法中每当程序需要获取该类的实例时,需要先判断全局变量是为nil
,如果不为nil
再进行变量的创建,并将变量赋值给该单例类。若不为nil
则直接返回全局变量的值。
方便我们查看我们声明的各类和各方法实现
这是对此篇学习笔记的总结与复习
alloc
)和初始化(init
),通常合并为[[Class alloc] init]
,对象的释放使用release
方法。-
)和类方法(使用+
),需要在接口部分声明并在实现部分提供具体实现。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。