黑马程序员——OC热身——概述、类、内存管理

——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平台的应用程序。

语法预览

  1. 没有命名空间(包名)概念
    没有命名空间机制,需要开发人员给类名加上前缀,以此来防止类名冲突。
    如NSString(OC中字符串类)、NSArray(OC中数组类),前缀都是NS。

  2. 关键字都以@开头
    为了防止跟C语言、C++关键字冲突,OC的关键字都以@开头。
    字符串也是以@开头。

  3. 语法要点
    这里写图片描述

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操作
retainsetter方法对参数进行release旧值,再retain新值
copysetter方法进行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的区别

  1. #import方式会包含被引用类的所有信息,包括被引用类中的变量和方法;@class只是告诉编译器有这个类,具体这个类里面有什么信息,这里不需要知道。等实现文件中真正用到这个类时,才会真正去查看这个类中的信息。
  2. 使用@class方式由于只需要知道被引用类的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以在 .m 文件中需要使用#import来包含被引用类的头文件。
  3. 如果有很多个头文件都#import了同一个文件,或者这些文件依次被#import,那么一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样效率较低。使用@class就不会出现这种问题了。
  4. 对于循环依赖关系来说,比如A类引用B类,B类也引用A类,在编译时会报错。使用@class互相声明就不会出错。

小结

如果是继承某个类,就要导入类的头文件。
如果只是定义成员变量、属性,用@class。

OC占位符

格式符意义
%iC语言中的%d,表示整数
%z无符号
%@代表打印一个OC对象,打印时会调用description方法

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值