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

封装概念及其原理



一个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可以修饰局部变量,在方法中可以保存方法上一次的运行结果(局部变量的生命周期延长)





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

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

Objective-C 学习笔记(Day 3,下)的更多相关文章

  1. 学习笔记(1)centos7 下安装nginx

    学习笔记(1)centos7 下安装nginx 这里我是通过来自nginx.org的nginx软件包进行安装的. 1.首先为centos设置添加nginx的yum存储库 1.通过vi命令创建一个rep ...

  2. Web安全学习笔记 SQL注入下

    Web安全学习笔记 SQL注入下 繁枝插云欣 --ICML8 SQL注入小技巧 CheatSheet 预编译 参考文章 一点心得 一.SQL注入小技巧 1. 宽字节注入 一般程序员用gbk编码做开发的 ...

  3. 一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx、supervisor、mysql环境搭建

    作为.neter,看到.net core 2.0的正式发布,心里是有点小激动的,迫不及待的体验了一把,发现速度确实是快了很多,其中也遇到一些小问题,所以整理了一些学习笔记: 阅读目录 环境说明 安装C ...

  4. CSS学习笔记四:下拉选择框以及其动画特效

    以前学的只是了解了css的一些基本属性,在做项目的时候都是直接使用bootstrap响应式来写项目,这样子很方便,很快捷,但是在自己看来还是有一点缺陷的,毕竟,我很多时候不怎么清楚它里面的具体运作.所 ...

  5. 《JavaScript权威指南》学习笔记 第二天 下好一盘大棋

    前段学习js的时候总是零零散散的,以至于很多东西都模棱两可.时间稍微一久,就容易忘记.最主要的原因是这些东西,原来学的时候就不是太懂,以至于和其他知识无法形成记忆链,所以孤零零的知识特别容易忘记.重温 ...

  6. 【计算机网络】 一个小白的网络层学习笔记:总结下IP,NAT和DHCP

    前言:这篇文章是学习网络层协议时候总结的笔记,前面的主要部分介绍的都是IP协议, 后半部分介绍NAT协议和DHCP协议 参考书籍 <计算机网络-自顶向下>       作者 James F ...

  7. redis学习笔记(一)——windows下redis的安装与配置

    前言 很久没有写东西了(.......我的水平就是记个笔记),北漂实习的我,每天晚上回来都不想动,但是做为社会主义接班人的我,还是要时刻给自己充充电,趁着年轻,趁着日渐脱发的脑袋还没有成为" ...

  8. 程序设计基础·Java学习笔记·面向对象(下)

    Java程序设计基础之面向对象(下) (补充了上的一些遗漏的知识,同时加入了自己的笔记的ヾ(•ω•`)o) (至于为什么分P,啊大概是为了自己查笔记方便(?)应该是("` 3′") ...

  9. Objective -C学习笔记之字典

    //字典:(关键字 值) // NSArray *array = [NSArray array];//空数组 // NSDictionary *dictionary = [NSDictionary d ...

  10. 【Android学习笔记】Mac下Android Studio开发环境搭建

    本文由@ray 出品,转载请注明出处.  文章链接:http://www.cnblogs.com/wolfray/p/7829069.html 对于移动端这块,笔者之前一直都是进行iOS开发的,也从来 ...

随机推荐

  1. 转载 DevOps的基本原则与介绍

    转载原地址:  http://www.cnblogs.com/wintersun/p/3339047.html DevOps的基本原则与介绍 DevOps这个术语是developer与operatio ...

  2. Altium Designer快捷键 【worldsing笔记】

    Shift + R 切换三种布线模式 (忽略, 避开或推挤) Shift + E 触发电气格点开/关 Shift + B 建立查询 Shift + PgUp 放大到最小的递增 Shift + PgDn ...

  3. After Android Studio update: Gradle DSL method not found: 'runProguard()'

    1 具体报错为: Error:(16, 0) Gradle DSL method not found: 'runProguard()' Possible causes:<ul><li ...

  4. js避免全局污染

    避免声明全局变量,以免发生冲突

  5. win10 64位安装mysql

    原文地址:http://blog.csdn.net/kingyumao/article/details/51925795

  6. cocos2d-x CCSpriteBatchNode

    转自:http://www.cnblogs.com/jiackyan/archive/2013/04/14/3019880.html 1.先说下渲染批次:这是游戏引擎中一个比较重要的优化指标,指的是一 ...

  7. fb设置viewSourceURL

  8. 【24】若所有参数皆需类型转换,请为此采用non-members函数

    1.令class支持隐式类型转换,往往是个糟糕的主意.但有些情况是合理的,比如数值类型.考虑,有理数Rational有分子,分母两个字段,缺省参数值为0,1.Ration a = 2;我们期望构造一个 ...

  9. CocoStudio 创建简单UI资源并加入�到project

    打开CocoStudio UI编辑器新项目,设置画布480*320, 加入�一个标签和一个button控件 导出项目,生成所须要的资源文件, 拷贝到cocos2dprojectResources文件夹 ...

  10. [React Fundamentals] Component Lifecycle - Mounting Usage

    The previous lesson introduced the React component lifecycle mounting and unmounting. In this lesson ...