4、Objective-C语言的面向对象特性

概述

Objective-C作为一种面向对象的编程语言,具有面向对象 的基本特征,即:封装、继承和多态。主要介绍Objective-C中有关面向对象基本概念:类、对象、方法和属性等。

Objective-C中的类

类是Objective-C中的一种重要的数据类型,是组成 Objective-C程序的基本要素。Objective-C的类声明和实现包括两个部分:接口部分和实现部分。

@interface Song: NSObject { 
    实例变量;
......
}
    方法的声明;
......
@end
@implementation Song 
方法的实现
code......
@end

接口部分

使用关键字@interface,主要定义了类名、继承的父类、实 现的协议、成员变量和方法等信息。下面的代码是Song类的 接口部分声明。

@interface Song : NSObject {
      NSString *title;
      NSString *artist;
      long int duration;
}
- (void)start;
- (void)stop;
- (void)seek:(long int)time;
@end

实现部分

使用关键字@implementation,主要实现了在接口部分定义 的方法等信息。下面的代码是Song类的实现部分声明。

@implementation Song
- (void)start { //开始播放
}
- (void)stop {
//停止播放 }
- (void)seek:(long int)time { //跳过时间
} 
@end

方法和消息

Objective-C中方法定义非常古怪,它遵循了SmallTalk语法 风格,它将一个方法名字分成几个部分。

说明

• 定义了两个参数的方法,第一个参数是anObject,参数类型 是id类型,第二个参数是index,参数类型是NSUInteger,这叫做多重参数。它的返回类型是void,方法签名是 insertObject:atIndex:。方法类型标识符中都“-”代表方法是实例方法,“+”代表方法是类方法,关于实例方法和 类方法我们将在后面内容中讨论。如果上面的方法变成C或C+ +形式,则是下面的样子的:
• -(void) insertObjectAtIndex(id anObject, NSUInteger index)

消息发送

对于方法的调用通常也不称之为调用,而是称为发出消息, 操作符号不是“.”而是“[⋯]”,如下所示:
这里写图片描述

[myObject insertObject: ojb1 atIndex:0];

即向myObject对象发出一个消息insertObject:atIndex:。 而在实际使用时候这两种叫法都会用,这不是严格划分。

访问成员变量

从面向对象的封装角度考虑问题,要想访问类中的成员变量 ,是要通过方法访问的,成员变量前面要有作用域限定符 (protected, public, private),这些存取权限修饰符我 们将在后面介绍。 成员变量的访问,是通过读取方法(getter)和设定方法(setter)。

Song.h文件

@interface Song : NSObject {
       NSString *title;
       NSString *artist;
       long int duration;
}
//操作方法
- (void)start;
- (void)stop;
-  (void)seek:(long int)time;
//访问成员变量方法
- (NSString *)title;
- (void)setTitle:(NSString *)newTitle;
- (NSString *)artist;
- (void)setArtist:(NSString *)newArtist; - (long int)duration;
- (void)setDuration:(long int)newDuration; 
@end

Song.m文件

@implementation Song
- (void)start {
//开始播放 
}
- (void)stop {
//停止播放
}
- (void)seek:(long int)time {
//跳过时间 ... ...//访问成员变量方法
- (NSString *)title {
       return title;
}
- (void)setTitle:(NSString *)newTitle {
       title = newTitle;
}
- (NSString *)artist {
       return artist;
}
- (void)setArtist:(NSString *)newArtist {
       artist = newArtist;
}
- (long int)duration {
       return duration;
}
- (void)setDuration:(long int)newDuration {
        duration = newDuration;
} 
@end

小结

采用了封装之后就可以通过存取方法访问属性,例如[mySong title]是取得title成员变量内容。
如果不考虑封装的问题,单从技术上讲Objective-C,可以 直接通过对象访问成员变量的,访问操作符是“->”,例如:
mySong->title,也可以取得title成员变量的内容。

属性

在上一小节中对于成员变量的访问,要通过读取方法 (getter)和设定方法(setter)。在实现部分也要实现这些读取方法和设定方法,为了简化这些琐碎编码Objective-C 2.0提出属性的概念,使用@property关键字在接口部分定义属性,在实现部分使用@synthesize关键字在组装和合成这 些属性。

Song.h文件

@interface Song : NSObject {
       NSString *title;
       NSString *artist;
       long int duration;
}
//操作方法
- (void)start;
- (void)stop;
- (void)seek:(long int)time;
//访问成员变量方法
@property(copy,readwrite) NSString *title; @property(nonatomic,retain) NSString *artist; 
@property(readonly) long int duration;
@end

说明

声明property的语法为:@property (参数) 类型 名字;, 这里的“参数”主要分为3大类:
•读写属性(readwrite/readonly);
•内存管理(assign/retain/copy),这些内存管理的参数,我们将在内存管理小节部分介绍;
•原子性atomicity(nonatomic),是关系线程线程安全的, atomicity是原子性的线程安全的,但是会影响性能。如果确定不考虑线程安全问题可以使用nonatomic。

Song.m文件

@implementation Song
@synthesize title;
@synthesize artist;
@synthesize duration;
- (void)start { 
 //开始播放
}
- (void)stop {
//停止播放
}
- (void)seek:(long int)time {
//跳过时间 
}
@end

构造方法

出于初始化类中的成员变量的需要,可以提供一个方法用于 此目的,这个方法就叫构造方法或构造方法 (Constructor)。与C++和Java不同,Objective-C命名是 没有限制的,并且有返回值本身类型指针。

Song.h文件

 @interface Song : NSObject {
       NSString *title;
       NSString *artist;
       long int duration;
}
//操作方法
- (void)start;
- (void)stop;
- (void)seek:(long int)time;
//访问成员变量方法
@property(nonatomic,retain) NSString *title; @property(nonatomic,retain) NSString *artist; @property(readwrite) long int duration; //构造方法
-(Song*) initWithTitle: (NSString *) newTitle andArtist: (NSString *) newArtist andDuration:( long int ) newDuration;
@end

说明

在Song类的定义中添加了一个方法,它一般用init开头命名 ,它的返回值很特殊,是返回值本身类型指针。并且有返回 值本身类型指针。

Song.m文件

@implementation Song
@synthesize title;
@synthesize artist;
@synthesize duration;
//构造方法
-(Song*) initWithTitle: (NSString *) newTitle
              andArtist: (NSString *) newArtist
                    andDuration:(long int)newDuration {
       self = [super init];
       if ( self ) {
               self.title = newTitle;
               self.artist = newArtist;
               self.duration = newDuration;
       }
       return self;
}
... ...
@end

说明

构造方法的实现代码几乎就是模式代码,基本上都是如下写法:

self = [super init];
if ( self ) {
...... 
}
return self;

说明

• 其中使用 [super init] 来调用父类默认构造方法。 这个 方法返回的实例对象指派给另一新个关键词:self。self 很像 C++ 和 Java 的 this。
• 还有if ( self ) 跟 ( self != nil ) 一样,是为了确定 调用父类构造方法成功返回了一个新对象。当初始化变量 以后,用返回self 的方式来获得自己的地址。
• 父类默认构造方法 -(id) init。技术上来说,Objective-C 中的构造方法就是一个 “init” 开头的方法,而不像 C++ 与 Java 有特殊的结构。

实例成员变量作用域限定符

• 即便从封装的角度出发,实例成员变量应该定义为 @private,但作为一种面向对象的语言,Objective-C支持@public、@private和@protected作用域限定。如果一个实 例变量没有任何的作用域限定的话,那么缺省就是 @protected。

• @public作用域限定的实例变量,可以在任何情况下访问;
• @private作用域限定的实例变量,只能在这个类里面才可 以访问;
• @protected作用域限定的实例变量,可以在这个类里面和 这个类的派生子类里面可以访问这个变量,在类外的访问是 不推荐的,但也可以访问。
实例成员变量作用域限定符

Access.h和Access.m文件

@interface Access: NSObject {
@public
       int publicVar;
@private
       int privateVar;
@protected
       int protectedVar;
} 
@end
#import "Access.h"
@implementation Access
@end

调用的main函数

#import <Foundation/Foundation.h>
#import "Access.h"
int main (int argc, const char * argv[]) {
       Access *a = [[Access alloc] init];
       a->publicVar = 5;
       NSLog(@"public var: %i\n", a->publicVar);
}
a->protectedVar = 6;
NSLog(@"protectedVar var: %i\n", a->protectedVar);
//不能编译
//a->privateVar = 10;
//NSLog(@"private var: %i\n", a->privateVar); return 0;

小结

@public、@private和@protected作用域限定只能修饰的实 例成员变量,不能修饰类变量,更不能修饰方法。

类变量和类方法
 类变量和类方法

ClassA.h文件

  #import <Foundation/NSObject.h>
static int count;
@interface ClassA: NSObject
+(int) initCount;
+(void) initialize;
@end

ClassA.m文件

#import "ClassA.h"
@implementation ClassA
-(id) init {
       self = [super init];
       count++;
       return self;
}
+(int) initCount {
       return count;
}
+(void) initialize {
       count = 0;
} 
@end

说明

init方法是默认构造方法,在这个构造方法中累计类变量 count,在实例方法中可以访问类变量的,但是类方法不能访问实例变量。initCount 方法是一个普通的类方法,用于 返回类变量count,initialize方法是非常特殊的类方法,它是在类第一次访问时候被自动调用,因此它一般用来初始 化类变量的,类似于C#中的静态构造方法。

调用的main函数

#import <Foundation/Foundation.h>
#import "ClassA.h"
int main( int argc, const char *argv[] ) {
       ClassA *c1 = [[ClassA alloc] init];
       ClassA *c2 = [[ClassA alloc] init];
       // print count
        NSLog(@"ClassA count: %i", [ClassA initCount] );
        ClassA *c3 = [[ClassA alloc] init];
        NSLog(@"ClassA count: %i", [ClassA initCount] );
        [c1 release];
        [c2 release];
        [c3 release];
        return 0;
}

//ClassA count: 2
//ClassA count: 3

小结

在第一次实例化ClassA时候会调用两个方法: initialize 类方法和实例构造方法init,然后再次实例化ClassA时候只是调用实例构造方法init,而没有调用initialize类方法。 这样类变量count被一直累加,它隶属类因此c1实例可以访问,c2和c3都可以访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值