——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——
Objective-C概述
Objective-C(简称OC) 是IOS开发的核心语言,在开发过程也会配合着使用C语言、C++,OC主要负责UI界面,C语言、C++可用于图形处理。
C语言是一门面向过程的语言,OC是在C语言的基础上,增加了一层最小的面向对象语法(将一些比较的面向对象语法都去掉了),剩下的都是面向对象的精华。
OC是基于C语言的,完全兼容C语言,也就是说在开发IOS程序的过程中,可以在OC代码中混入C语言代码和C++代码。
可以使用OC开发Mac OS X平台和IOS平台的应用程序。
语法预览
没有命名空间(包名)概念
没有命名空间机制,需要开发人员给类名加上前缀,以此来防止类名冲突。
如NSString(OC中字符串类)、NSArray(OC中数组类),前缀都是NS。关键字都以@开头
为了防止跟C语言、C++关键字冲突,OC的关键字都以@开头。
字符串也是以@开头。- 语法要点
类
OC中类分为两个文件
.h:类的声明文件,用于声明变量、函数(方法)
.m:类的实现文件,用于实现 .h 中的函数(方法)
//Student.h
#import <Foundation/Foundation.h>
//@interface代表声明一个类
//: 代表继承
@interface Student : NSObject {
//成员变量要定义在这
int age;
}
//在这里声明的所有方法都是公共的
//age的get方法
//OC中类型用()括住
// - 代表对象方法 + 代表静态方法
- (int)age;
//age的set方法
//OC中一个 : 代表一个参数
- (void)setAge:(int)newAge;
@end
#import "Student.h"
@implementation Student
- (int)age{
return age;
}
- (void)setAge:(int)newAge{
age = newAge;
}
@end
#import <Foundation/Foundation.h>
#import "Student.h"
int main()
{
@autoreleasepool{
//创建一个Student对象
//1.调用一个静态方法alloc来分配内存
//Student *stu = [Student alloc];
//2.调用一个动态方法init进行初始化
//stu = [stu init];
Student *stu = [[Student alloc] init];
[stu setAge:100];
int age = [stu age];
NSLog(@"age = %i",age);
//释放对象
[stu release];
}
return 0;
}
点语法
点语法是Xcode编译器提供的为了让java,C#等程序员更好上手OC扩展的语法。
点语法的本质是调用set方法或调用get方法。
点语法会在编译时退化为OC的方法调用语句。
//此处调用的是setAge方法,并不是直接为成员变量age赋值
person.age = 10; //等效于[person setAge:10];
//此处调用的是getAge方法
int age = person.age; //等效于[person age];
为什么不能写self.age = newAge;
- (void)setAge:(int)newAge{
age = newAge;
//这是错误的写法,会导致死循环,无限调用set方法
//self.age = newAge; // [self setAge:newAge];
}
为什么要设计点语法?
1. 方便程序员快速入手OC。
2. 简化程序设计。
3. 隐藏了内存管理细节。
4. 隐藏了多线程、同步、加锁细节。
构造方法
用于对象的初始化
- (id)initWithAge:(int)age andNo:(int)no {
//首先调用父类的构造方法
self = [super init];
//如果self不为nil
//简化:if(self = [super init])
if(self){
//_age = age;
//_no = no;
self.age = age;
self.no = no;
}
//返回对象的指针
return self;
}
description方法
当使用%@打印一个对象的时候,会调用这个方法
//重写父类的description方法
- (NSString*)description{
NSString *str = [NSString stringWithFormat:@"age is %i",self.age];
return str;
}
变量的作用域
@public 全局都可以访问
@protected 只能在类内部和子类中访问
@private 只能类内部访问
成员变量默认是protected的
@property
@property会自动生成setter和getter的声明
//当编译器遇到@property时,会自动展开成setter和getter的声明
@property int age;
//- (void)setAge:newAge;
//- (int)age;
@property参数
@property (参数1,参数2) 类型 名字;
读写属性: (readwrite/readonly)
setter语意:(assign/retain/copy)
原子性: (atomicity/nonatomic)
//release旧值,retain新值
@property(nonatomic,retain) (int)age;
//getter代表重命名get方法
@property(nonatomic,getter = isRich) (BOOL)rich;
参数 | 意义 |
---|---|
readwrite | 产生setter\getter方法 |
readonly | 只产生简单的getter,没有setter |
assign | 默认类型,setter方法直接赋值,而不进行retain操作 |
retain | setter方法对参数进行release旧值,再retain新值 |
copy | setter方法进行Copy操作,与retain一样 |
nonatomic | 禁止多线程,变量保护,提高性能 |
atomic | 代表给方法进行加锁,保证线程安全 |
@synthesize
@synthesize会自动生成setter和getter的实现
//@synthesize默认会去访问跟age同名的同名变量
//如果找不到同名的变量,会自动生成一个私有的同名变量age
//@synthesize age;
//age = _age代表getter和setter会去访问_age这个成员变量
@synthesize age = _age;
在xcode4.5环境下,可以省略@synthesize,并且默认会去访问_age这个成员变量。
如果找不到_age这个成员变量,会自动生成一个叫做_age的私有成员变量
小结
1. 谁调用方法,self就指向谁。
2. 如果直接把方法写在 .m 文件中,没有在 .h 文件中进行声明,那么这就是私有方法。
内存管理
任何继承了NSObject的对象,都需要进行内存管理。
本质原因是因为对象和其他数据类型在系统中的存储空间不一样,其它局部变量主要存放于栈中,而对象存储于堆中,当代码块结束时这个代码块中涉及的所有局部变量会被回收,指向对象的指针也被回收,此时对象已经没有指针指向,但依然存在于内存中,造成内存泄露。
原理
每个对象内部都保存了一个与之相关联的整数,称为引用计数器。当使用alloc、new或者copy创建一个对象时,对象的引用计数器被设置为1。
当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收,OC也会自动向对象发送一条dealloc消息。一般会重写dealloc方法,在这里释放相关资源。一定不要直接调用dealloc方法。
可以给对象发送retainCount消息获得当前的引用计数器值。
retain和release
给对象发送一条retain消息,可以使引用计数器值+1。
给对象发送一条release消息,可以使引用计数器值-1。
Student *stu = [[Student alloc] init];
[stu release];
//[stu release]; 发生野指针错误
内存释放后,重复调用release方法,会发生野指针错误,也就是说访问了不属于你的内存。
判断对象要不要回收的唯一依据就是计数器是否为0,若不为0则存在。
对象之间的内存管理(set方法的内存管理)
- (void)setBook:(Book*)book{
//先判断是不是新传进来的对象(防止出现野指针错误)
if(_book != book)
{
//对旧对象做一次release操作
[_book release];
//对新对象做一次retain操作
book = [book retain];
}
}
自动释放池(autorelease pool)
自动释放池是OC提供的一种内存自动回收机制,一般可以将一些临时变量添加到自动释放池中,统一回收释放。
当自动释放池销毁时,池里面所有的对象都会调用一次release方法。
int main()
{
//@autoreleasepool代表创建一个自动释放池
@autoreleasepool{
Student *stu = [[Student alloc] init];
//autorelease并不会改变引用计数器的值
[stu autorelease];
}
return 0;
}
注意:
1. 在ARC下,不能使用 [[ NSAutoreleasePool alloc ] init ](在5.0以前可以使用),而应该使用@autoreleasepool。
2. 不要把大量循环放在autoreleasepool中,这样会造成内存峰值上升,因为里面创建的对象要等释放池销毁了才能释放,这种情况应该手动管理内存。
3. 尽量避免大内存使用该方法,对于这种延迟释放机制,尽量少用。
4. SDK中利用静态方法创建并返回的对象都已经autorelease,不需要我们自己手动release。
内存管理原则
只要还有人在使用某个对象,那么这个对象就不会被回收;
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;
当你不想使用这个对象时,应该让对象的引用计数器-1;
谁创建,谁release:如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者autorelease方法。不是你创建的就不用你去负责。
谁retain,谁release:只要你调用了retain,无论这个对象时如何生成的,你都要调用release。
有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1。
@class关键字
引入一个类通常有两种方法,一种是通过#import引入,一种是用@class引入。
#import和@class的区别
- #import方式会包含被引用类的所有信息,包括被引用类中的变量和方法;@class只是告诉编译器有这个类,具体这个类里面有什么信息,这里不需要知道。等实现文件中真正用到这个类时,才会真正去查看这个类中的信息。
- 使用@class方式由于只需要知道被引用类的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以在 .m 文件中需要使用#import来包含被引用类的头文件。
- 如果有很多个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样效率较低。使用@class就不会出现这种问题了。
- 对于循环依赖关系来说,比如A类引用B类,B类也引用A类,在编译时会报错。使用@class互相声明就不会出错。
小结
如果是继承某个类,就要导入类的头文件。
如果只是定义成员变量、属性,用@class。
OC占位符:
格式符 | 意义 |
---|---|
%i | C语言中的%d,表示整数 |
%z | 无符号 |
%@ | 代表打印一个OC对象,打印时会调用description方法 |
——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——