面向对象的学习

Objective-C 面向对象

Objective-C是面向对象的程序设计语言,它提供了定义类、成员变量、方法的基本功能,类可被认为是一种自定义的数据类型。
类用于描述客观世界中某一类对象的共同特征,而对象则是类的具体存在。
面向对象的三大特征为:封装,继承,多态。
以上都是面向对象学习中所要了解的知识。
重点可以参考书本上的要点总结,但本博客不会按要点顺序解读
在这里插入图片描述

类和对象

类可以当作定义变量和方法的自定义数据类型,所有的类都是指针类型的变量。

定义类

类与对象是面向对象的核心。
定义类分为两个步骤:1.接口部分,2.实现部分
接口部分对成员变量和方法进行声明,声明如下
在这里插入图片描述

在这里插入图片描述
声明中其他元素与c差不多,格式有所不同,其他要注意的点:1.成员变量名前缀为_2.方法声明中’-'代表实例方法,允许对象调用,‘+’代表类方法,允许类名调用3.方法声明中所有的类型都应该用圆括号括起来。4.且注意foo foo: foo:andage 不是同一种方法,可以同时定义
实现部分1.类实现部分的类名与接口处相同2.类名后的冒号表示继承了一个父类3.类实现部分定义的变量只能在当前类访问4.提供方法定义
在这里插入图片描述
这里体现了封装意识,接口部分相当于暴露在外,而实现部分则隐藏在内。

#import <Foundation/Foundation.h>
@interface FKperson : NSObject {
    NSString* _name;
    int _age;
}
- (void) setName : (NSString*) n andage : (int) a;
- (void) say : (NSString*) m;
- (NSString*) info;
+ (void) foo;
@end

@implementation FKperson
- (void) setName:(NSString *)n andage:(int)a {
    _name = n;
    _age = a;
}

- (void) say : (NSString*) m {
    NSLog(@"%@", m);
}
- (NSString*) info {
    [self test];
    return [NSString stringWithFormat:@"我是一个人, 我的名字是%@, 年龄是%d",_name, _age];
    //[NSString stringWithFormat:    ]该方法返回-个NSString型的指针
}
- (void) test {
    NSLog(@"只在实现部分定义实现的test方法");
}
+ (void) foo {
    NSLog (@"FKperson 类的类方法,通过类名调用");
}

@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        id w = [[FKperson alloc] init];//id类型变量可以赋予任何类的对象
        [w setName:@"朱敬业" andage:18];
        [w say:@"Hello I Like iOS"];
        NSString* p = [w info];
        NSLog(@"%@",p);
        [FKperson foo];
    }
    return 0;
}

以上是一个已经定义的类,和类的使用,重点注意一下test方法,这是一个定义在实现部分的方法,因此这个方法不允许在main中调用,至允许在类中使用;
以及FKperson中的形参标签,只是为了说明后面的形参,不对形参限制

对象的产生和使用

对类的使用有三个方面1.定义对象2.创建对象3.调用类方法,
参考上面的代码:
id w是对象的定义,[[FKperson alloc] init]是对象的创建,类比c语言的初始化,[w setName:@“朱敬业” andage:18];
[w say:@“Hello I Like iOS”];则是对类方法的调用
如果方法中申明了形参,要为形参赋值
方法可以参考函数,它同样具有形参和返回值,但对象不同

对象和指针

id w = [[FKperson alloc] init];
这里定义了一个w指针,它指向了内存中的对象,因此,如果堆内存中的对象没有任何变量指向对象,那么程序将无法访问该对象。
这就是对象和指针的关系

self关键字

self关键字总是指向该方法的调用者,在实例方法中self代表该方法的对象,类方法中代表该方法的类
self最大的作用是让类中的一个方法访问该类的另一个方法和变量在这里插入图片描述
当成员变量被形参隐藏是,也可以使用self来区分和访问
在这里插入图片描述
可以直接使用self作为返回值,是代码更加简洁,但可能造成实际意义的模糊

id类型

任意的对象都可以赋值给id类型的变量
其不在编译时确定,而在运行时判断对象所属的类

方法详解

方法由传统函数发展过来,但与传统函数有所不同,如方法必须属于类或对象

方法的属性

方法不能独立定义,只能在类中定义
方法要么属于类,要么属于对象
不能独立调用方法,需要调用者

形参个数可变的方法

在这里插入图片描述
代码如下:

#import <Foundation/Foundation.h>
@interface Varargs : NSObject
- (void) test : (NSString*) name, ... ;
@end

@implementation Varargs

- (void) test:(NSString *)name, ... {
    va_list m ;
    va_start(m, name);
    NSLog (@"%@",name);
    NSString* s;
    s = va_arg(m, id);
    while (s) {
        NSLog(@"%@",s);
        s = va_arg(m, id);
    }
    va_end(m);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        id w = [[Varargs alloc] init];
        [w test:@"疯狂iOS讲义", @"疯狂anadroid讲义",@"疯狂ajax讲义",nil];
    }
    return 0;
}

这里要注意name不是可变形参,因此m一开始指向name的后一个。
一个方法最多只有一个个数可变的形参。

成员变量

变量分为三大类:成员变量,局部变量,全局变量

成员变量及其运行机制

成员变量指的是接口和实现部分定义的变量,Objective-c的成员变量都是实例变量
可以用实例->实例变量来访问成员变量
在这里插入图片描述
id w = [[Varargs alloc] init];
程序会为FKperson对象的成员分配空间并执行默认的初始化,然后把FKperson这个对象付给p变量;
从内存存储角度来看,Objective-C的对象与前面介绍的C结构体相似,具体可以参照这两个图
在这里插入图片描述

隐藏与封装

理解封装

封装指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内的信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
对一个类或对象进行良好的封装,可以实现以下目的
在这里插入图片描述
封装的意义:把该隐藏的隐藏起来,该暴露的暴露出来

使用访问控制符

四个访问控制符:@private,@package,@protect,@public
控制关系如图:
在这里插入图片描述
在这里插入图片描述

对于局部变量而言,其作用域就是它所在的方法,不可能被其他类访问,因此,不能使用控制访问符来修饰//

#import <Foundation/Foundation.h>
@interface FKperson : NSObject {
    @private
    NSString* _name;
     int _age;
}
- (void) setName : (NSString*) n ;
- (NSString*) name;
- (void) setAge :(int) a;
- (int) age;
@end

@implementation FKperson

- (void) setName: (NSString*) n {
    if ([n length] > 6 || [n length] < 2) {
        NSLog(@"名字格式不对");
    } else {
        _name = n;
    }
    return;
}
- (NSString*) name {
    return _name;
}
- (void) setAge:(int)a {
    if (a > 100 || a < 0) {
        NSLog(@"年龄不对");
    } else {
        _age  = a;
    }
    return;
}
- (int) age {
    return _age;
}
@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        FKperson* w = [[FKperson alloc] init];
        [w setName:@"朱敬业"];
        [w setAge:19];
        w->_age = 16;
        NSLog(@"%@ %d", [w name], [w age]);
    }
    return 0;
}

以上代码由于使用了@private,所以w->_age = 16;会报错,因为@private只允许在类中访问,相当于隐藏于类中,在外面无法访问,只能用方法间接访问;
@proteced则允许子类访问父类的成员变量;
@package我理解为可以访问同框架内的变量,如把类的接口部分和实现部分和main函数放在一起,可以直接访问
@public则几乎没有限制了
模块设计追求高内聚低耦合,所以在封装中满座以下原则
在这里插入图片描述

合成存取方法

也就是setter,getter,可以对对象的成员变量通过方法进行赋值和读取;但也可以自动合成setter和getter;
即在类接口部分使用@property指令定义属性。
在实现部分使用@synthesize合成方法;
其使用可以参考以下代码

#import <Foundation/Foundation.h>
@interface FKuser : NSObject
@property (nonatomic, copy) NSString* name;
@property (nonatomic) int age;//copy指示符只能用于类
@property (nonatomic, copy) NSString* address;
@end

@implementation FKuser

@synthesize name;
@synthesize age;
@synthesize address;
- (id) init {
    if (self = [super init]) {
        self.name = @"孙悟空";
        self.address = @"花果山";
        self.age = 500;
    }
    return self;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        FKuser* w = [[FKuser alloc] init];
        NSLog(@"%@ %d %@",w.name, w.age, w.address);
    }
    return 0;
}

上面的代码中
NSLog(@“%@ %d %@”,w.name, w.age, w.address);
'.'实际上是对setter和getter的使用
@property和类型之间有特殊指示符,如下
在这里插入图片描述
在这里插入图片描述

对象初始化

可以参考指针的初始化;
每次创建对象时都要用alloc来分配空间,然后用方法来初始化对象;

为对象分配空间

[类名 alloc]可以为对象分配空间,并将每个实例变量的内存空间重置为0或nil;

初始化方法与对象初始化

在实现部分重新定义init方法可以重写NSObject中的init方法,也可以自己定义新的方法来实现自定义初始化;

#import <Foundation/Foundation.h>
@interface FKcar : NSObject
@property (nonatomic, copy) NSString* brand;
@property (nonatomic, copy) NSString* model;
@property (nonatomic, copy) NSString* color;
- (id) initWithBrand : (NSString*) brand model:(NSString*) model;
- (id) initWithBrand : (NSString*) brand model:(NSString*) model color:(NSString*) color;
@end

@implementation FKcar

@synthesize brand;
@synthesize model;
@synthesize color;
- (id) init {
    if (self = [super init]) {
        self.brand = @"奥迪";
        self.model = @"Q5";
        self.color = @"黑色";
    }
    return self;
}
- (id) initWithBrand:(NSString *)brand model:(NSString *)model {
    if (self = [super init]) {
        self.brand = brand;
        self.model = model;
        self.color = @"黑色";
    }
    return self;
}
- (id) initWithBrand:(NSString *)brand model:(NSString *)model color:(NSString *)color {
    if (self = [self initWithBrand:brand model:model]) {
        self.color = color;
    }
    return self;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...NSLog(@"Hello, World!");
        FKcar* a =[[FKcar alloc] init];
        FKcar* b = [[FKcar alloc] initWithBrand:@"奔驰" model:@"ML350"];
        FKcar* c = [[FKcar alloc] initWithBrand:@"宝马" model:@"x5" color:@"black"];
        NSLog(@"%@ %@ %@",a.brand,a.model,a.color);
        NSLog(@"%@ %@ %@",b.brand,b.model,b.color);
        NSLog(@"%@ %@ %@",c.brand,c.model,c.color);
    }
    return 0;
}

类的继承

继承的特点

子类是一种特殊的父类
语法格式如下:
在这里插入图片描述
子类可以继承父类的全部变量和方法
每个类最多只有一个直接父类,但可以有多个间接父类,NSObject是所有子类的父类,所以都可以使用它的方法,有点像头文件;
子类扩展了父类,父类派生了子类。

重写父类的方法

即在子类的实现部分重新定义父类重名的方法,可以隐藏父类的方法。这种方法叫做方法重写,也叫方法覆盖;
在这里插入图片描述

super关键字

super用于限定该对象调用从父类继承得到的属性和方法。
在这里插入图片描述
在继承时,子类不能定义与父类接口部分重名的成员变量
super关键字强制调用父类的属性,可以访问被覆盖掉的父类属性;
在这里插入图片描述

多态

指针类型变量有两个:编译时类型,运行时类型。如果编译型类型和运行时类型不一致,就可能出现多态;

多态性

Objective-c允许把一个子类对象直接赋值给父类指针变量,无需类型转化,自动实行;,这是可能出现相同类型变量调用同一个方法时呈现多种不同的行为特征,这也就是多态,为了解决编译时类型检查的问题,可以使用id类型;

指针变量的强制类型转换

强制类型转化只是该改变了编译时类型,但变量所指向对象的实际类型不会改变,不加判断的转化会引发错误;如下在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值