Objective-C 学习笔记(Day 3,下)

———————————————————————————————————————————
封装概念及其原理

一个Gun类的例子来详细说明这一环节:

#import <Foundation/Foundation.h>

@interface Gun : NSObject
{
    @public
    int _bulletCount;
}
-(void)shoot;//这是射击的方法,前提是有子弹(子弹>=0),子弹数目<0则没有意义,我们要让方法整体符合逻辑。
-(void)setGunBullet:(int)bullet;//我们虽然可以在shoot方法中将子弹数目的判定写上,但是这样做有一点点不符合常理。这是因为如果我们只写一个shoot方法,而我们传的值为-3,然后让shoot去接收-3这个值判断,如果在shoot方法内先打印一下子弹数,很明显子弹数为-3是不对的,是不安全的。我们根本不需要去接收这个不正确的值,接收了说明不严谨。所以说我们需要一个方法去预处理一下子弹的个数,这也是体现的封装的思想。
@end

@implementation Gun
-(void)shoot
{
    if (_bulletCount>0) {
        _bulletCount--;
        NSLog(@"tututu ...");
    }
    else
    {
        NSLog(@"No bullet!");
    }
}

-(void)setGunBullet:(int)bullet
//在setGunBullet:方法中,我们先接收输入的值判断,然后再将处理过的值传给实例变量_bulletCount,处理之后的值肯定是>=0的,符合了子弹数目的逻辑(有子弹>0,没有子弹=0)
{
    if (bullet>0) {
        _bulletCount=bullet;
    }
    else
    {
        _bulletCount=0;
    }
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Gun *gun=[[Gun alloc]init];
        
        [gun setGunBullet:3];
        
        [gun shoot];
        [gun shoot];
        [gun shoot];
        [gun shoot];
        [gun shoot];
    }
    return 0;
}


———————————————————————————————————————————
封装的实现步骤

★★★这一部分是重点哦!重点记忆!★★★

★定义    设置实例变量(setter)方法    和    访问实例变量(setter)方法,在这里我们可以通俗的将set记为设置成员变量的值,将get记为获取成员变量的值。
(这里的实例变量就是声明类的时候的属性成员变量,叫法很多)

(1)setter方法(设置器)

在开发过程中,出于安全性的考虑,我们不会在成员变量名的前面使用 @public 、@protected 等关键字进行修饰,而是使用set方法来为对象提供成员变量的值,在set方法的内部也对一些不合理的赋值进行过滤。

set方法的作用:为外界提供一个设置成员变量值的方法。

★set方法的命名规范:
①set方法一定是一个对象方法( - 号开头)
②set方法一定 没有返回值(返回值为void类型)
③set方法的方法名必须set开头
④set方法的方法名在 写完set开头 后应该跟成员变量名去掉下划线后首字母大写的单词
(如:成员变量名为 _name,那么set方法名为 setName)
⑤set方法必须有参数,而且参数的类型要和该成员变量的类型保持一致
⑥参数的参数名是成员变量名去掉下划线后的单词
(如:成员变量名为 _age,那么set方法的参数名为 age。苹果官方推荐 成员变量名 前面加下划线  “ _ ”  以示区分)
⑦形参名不能和成员变量名同名(这一条和第⑥条差不多)
⑧set方法实现一定要通过形参给成员变量(实例变量)赋值(这也是set方法的作用~)


(2)getter方法(访问器)

get方法的作用:为外界提供一个获取(返回、得到)成员变量值的方法

★get方法的命名规范:
①get方法一定是一个对象方法 ( - 号开头)
②get方法一定 有返回值,且返回值类型和成员变量的类型一致
③get方法的方法名是去掉下划线的成员变量名
(如:成员变量名为 _name,那么get方法名为name,★注意没有get开头★,这里是和java不一样的)
④get方法一定没有参数
⑤get方法实现一定是返回(获取)成员变量(实例对象)的值

下面一个Person类的例子向大家详细介绍set、get方法的定义与使用:

#import <Foundation/Foundation.h>
typedef enum {kSexMan,kSexWoman,kSexYao}Sex;
@interface Person : NSObject
{
    NSString *_name;
    Sex _sex;
    int _age;
    float _height;
}

//以后设置(赋值)_name、_sex 等等成员变量(实例变量)的值,都统一使用其set方法
//_name的set方法
-(void)setName:(NSString *)name;
//_sex的set方法
-(void)setSex:(Sex)sex;
//_age的set方法
-(void)setAge:(int)age;
//_height的set方法
-(void)setHeight:(float)height;

//以后访问(获取)_name、_sex 等等成员变量(实例变量)的值,都统一使用其get方法
//_name的get方法
-(NSString *)name;
//_sex的get方法
-(Sex)sex;
//_age的get方法
-(int)age;
//_height的get方法
-(float)height;

@end


@implementation Person

//-----------------------set 方法的实现-----------------------
//_name的set方法
-(void)setName:(NSString *)name
{
    _name=name;
}

//_sex的set方法
-(void)setSex:(Sex)sex
{
    _sex=sex;
}

//_age的set方法
-(void)setAge:(int)age
{
    _age=age;
}

//_height的set方法
-(void)setHeight:(float)height
{
    _height=height;
}

//-----------------------get 方法的实现-----------------------
//_name的get方法
-(NSString *)name
{
    return _name;
}

//_sex的get方法
-(Sex)sex
{
    return _sex;
}

//_age的get方法
-(int)age
{
    return _age;
}

//_height的get方法
-(float)height
{
    return _height;
}

@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p=[Person new];
//        以后我们对实例变量操作都要用set、get方法,封装之后安全性高
        [p setName:@"wang"];//调用_name的set方法,为其实例变量赋值
        NSLog(@"name:%@",[p name]);//调用_name的get方法,获取返回值,并打印出来
        
        [p setAge:21];
        NSLog(@"name:%d",[p age]);
        
        [p setSex:kSexMan];
        NSLog(@"name:%d",[p sex]);
        
        [p setHeight:179.5];
        NSLog(@"name:%.2f",[p height]);
    }
    return 0;
}


———————————————————————————————————————————
封装的应用案例(股票k线计算)

#import <Foundation/Foundation.h>

@interface KLine : NSObject
{
    float _minPrice;//最低股价,可读(get)写(set)
    float _maxPrice;//最高股价,可读写
    float _avPrice;//平均股价,只读(get)
}
-(void)setMinPrice:(float)minPrice;
-(float)minPrice;

-(void)setMaxPrice:(float)maxPrice;
-(float)maxPrice;

-(float)avPrice;
@end

@implementation KLine
-(void)setMinPrice:(float)minPrice
{
    _minPrice=minPrice;
    _avPrice=(_maxPrice+_minPrice)/2;//我们在_minPrice和_maxPrice的set方法中都加了一句计算平均值的语句,这样的话很好的向大家展示出只要两个值的其中一个发生了改变,平均值就立马发生变化,而不是等到我们读_avPrice的时候才发生变化。这样的写法才更符合逻辑
}
-(float)minPrice
{
    return _minPrice;
}

-(void)setMaxPrice:(float)maxPrice
{
    _maxPrice=maxPrice;
    _avPrice=(_maxPrice+_minPrice)/2;
}
-(float)maxPrice
{
    return _maxPrice;
}

-(float)avPrice
{
//    _avPrice=(_maxPrice+_minPrice)/2;
//    我们完全可以直接在实例变量_avPrice的get方法内写上面这一句,这样只要_minPrice或者_maxPrice发生了变化,那么_avPrice的值就发生变化,但是这样意义体现的不是很明确。
    return _avPrice;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        KLine *kline=[KLine new];
        
        [kline setMaxPrice:55.9];
        [kline setMinPrice:23.8];
        
        NSLog(@"avPrice:%.2f",[kline avPrice]);
    }
    return 0;
}


我觉得上面这个程序需要着重注意的地方有两点:
①可读写的意思:读(get),写(set)
②注意在取平均值的时候,一定要符合逻辑性,结果可能都是一个样子,但是怎么出来的结果要格外严谨!


———————————————————————————————————————————
依赖关系

下面通过一个简短的小程序来解释一下这一部分。

#import <Foundation/Foundation.h>

@interface IPhone : NSObject
{
    NSString *_phoneNum;
}
-(void)setPhoneNum:(NSString *)phoneNum;
-(void)callPhone;
-(void)sendMessage;
@end

@interface Girl : NSObject
-(void)callPhoneToTuhao:(IPhone *)phone;
-(void)sendMessageToTuhao:(IPhone *)phone;
@end

@implementation IPhone
-(void)setPhoneNum:(NSString *)phoneNum
{
    _phoneNum=phoneNum;
}
-(void)callPhone
{
    NSLog(@"给土豪打电话,电话为:%@",_phoneNum);
}
-(void)sendMessage
{
    NSLog(@"给土豪发短信,电话为:%@",_phoneNum);
}
@end

@implementation Girl
-(void)callPhoneToTuhao:(IPhone *)phone
{
    [phone setPhoneNum:@"18363861160"];
    [phone callPhone];
}
-(void)sendMessageToTuhao:(IPhone *)phone
{
    [phone setPhoneNum:@"18363861160"];
    [phone sendMessage];
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //有这么两个类:Girl和IPhone
        //美女要通过电话给土豪联系,所以说美女依赖于电话,电话是美女打电话时的一个参数!
        IPhone *ip7=[IPhone new];
        
        Girl *girl=[Girl new];
        
        [girl callPhoneToTuhao:ip7];
        [girl sendMessageToTuhao:ip7];
    }
    return 0;
}


//ip7           girl
//A对象   作为   B对象   的局部变量或者是方法形参时,B依赖于A,如刚刚的我们写的程序:
//[girl callPhoneToTuhao:ip7]    girl对象依赖于ip7对象


———————————————————————————————————————————
关联关系

下面通过一个简短的小程序来解释一下这一部分。

#import <Foundation/Foundation.h>

@interface IPad : NSObject
{
    NSString *_name;
}
-(void)setName:(NSString *)name;

-(void)showMusic;
-(void)showMovie;
-(void)playGames;
@end

@interface Person : NSObject
{
    NSString *_name;
    IPad *_ipad;
}
-(void)setName:(NSString *)name;
-(void)setIPad:(IPad *)ipad;

-(void)listenMusic:(IPad *)ipad;
@end

@implementation IPad
-(void)setName:(NSString *)name
{
    _name=name;
}

-(void)showMusic
{
    NSLog(@"正在用%@播放音乐!",_name);
}

-(void)showMovie
{
    NSLog(@"正在用%@看电影!",_name);
}

-(void)playGames
{
    NSLog(@"正在用%@打游戏!",_name);
}
@end

@implementation Person
-(void)setName:(NSString *)name
{
    _name=name;
}

-(void)setIPad:(IPad *)ipad
{
    _ipad=ipad;
}

-(void)listenMusic:(IPad *)ipad//在listenMusic方法内部我只写了一个showMusic方法,剩下的读者可以自行添加。
{
    [ipad showMusic];
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p=[Person new];
        
        IPad *i=[IPad new];
        
        [i setName:@"ipad123"];
        
        [p setName:@"wangzhongyao"];
        [p setIPad:i];
        [p listenMusic:i];
    }
    return 0;
}

这一部分也是很重要的,和依赖关系差不多,经常用到,记住里面类之间是怎么调用的。其实仔细看看就会发现,每个类只管自己的事情,需要什么就去拿什么,一个类需要另一个类就要加上所需的头文件,设置形参啊什么的也都一样,需要就设。慢慢理解,慢慢熟悉整个过程。还有一点,赋值一定要用set方法,记住记住!可能一开始不适应,长时间就好了!上面几个程序没有get方法,因为我们没有用到。


———————————————————————————————————————————
方法重载

★OC里面没有方法重载!
★在OC中方法名是不允许相同的!(与java不一样)

-(void)run:(int)a;
-(void)run:(float)a;   //Duplicate declaration of method 'run:'   显然无法同名

注意:

①   -(void)run:(int)num1;   //方法名是   run:

②   -(void)run:(int)num1 and:(float)num2;   //方法名是   run:   and:

③   -(void)run:(int)num1 : (int)num2 : (int)num3;   //方法名是   run:   :   :

以上三个方法是可以同时存在的,因为方法名不同,尤其要注意第三个。


———————————————————————————————————————————
static关键字的使用

这一部分的知识不是很系统,大家在用到这方面的时候试一试就可以明确了。如果没错误说明可以使用,有错误自然无法使用,希望大家灵活学习。

#import <Foundation/Foundation.h>
static int num2=20;//定义全局变量也是可以的
@interface Dog : NSObject
{
    //   static int _speed;  这是错误的
    
    //实例变量不能声明为静态
    //在C语言中
    //没有初始化的静态变量存在BSS段
    //如果已经初始化了,存在数据区
}

-(void)run;
@end

@implementation Dog

-(void)run
{
    static int num1=10;//定义静态局部变量,是可以的
    
    NSLog(@"num=%d",num1);
    num1++;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog *dog=[Dog new];
        [dog run];
        [dog run];
        [dog run];
        [dog run];//在run方法中num是静态的局部变量,所以每执行一次run方法,num++,num的值会改变。如果不定义成静态的,那么上面多次调用run方法,num值也是不会改变的
        NSLog(@"num2=%d",num2);
    }
    return 0;
}


★总结一下:
①static不能修饰类的方法
②static不能修饰类的实例变量
③static可以修饰全局变量,但是只能在本文件中使用
④static可以修饰局部变量,在方法中可以保存方法上一次的运行结果(局部变量的生命周期延长)


———————————————————————————————————————————

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-08-21 09:37  王中尧  阅读(175)  评论(0编辑  收藏  举报