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

封装概念及其原理



一个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. ASP.NET- 执行SQL超时的解决方案

    在我们编写程序的时候,有时候要进行复杂的查询时,就会出现执行sql时间过长,引起页面执行不了并提示执行脚本超时,这就是我们遇到超时异常. 超时异常分两种情况:一种,是连接超时:一种,是执行超时.前者, ...

  2. Unable to resolve module LinkedStateMixin

    由于前面reactive文件夹的删除,导致运行程序的时候出现Unable to resolve module LinkedStateMixin 的错误. 搞了好久都没办法解决,看来不深入其中,无法解决 ...

  3. Why Does Everyone Else Appear to Be Succeeding?

    Why Does Everyone Else Appear to Be Succeeding?  —Steven G. Krantz When you are a student, it will a ...

  4. linux下配置squid http proxy过程

      国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国 ...

  5. 判断数组(array)中是否包含某个字符(contains)

    $a="a","","b" $a -contains "a" 返回 $true $a -notcontains &quo ...

  6. JAVA线程全局异常处理

    大家平时写线程很多,但可能很少关注如何捕获线程的全局异常.其实jdk提供了两种捕获全局异常的方法,一种是基于整个线程类(staticsetDefaultUnaughtExceptionHandler( ...

  7. SCSS loader effect

    p{text-indent:2em;}前端开发whqet,csdn,王海庆,whqet,前端开发专家 几天来看一组利用SCSS实现的loader effect(载入效果).鼓舞大家自行动手实现,当然也 ...

  8. Codeforces Round #324 (Div. 2) D. Dima and Lisa 哥德巴赫猜想

    D. Dima and Lisa Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/584/probl ...

  9. BZOJ 2241: [SDOI2011]打地鼠 暴力

    2241: [SDOI2011]打地鼠 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pro ...

  10. Android手机上判断网络运营商

    我们想获取手机的运营商信息.通常都会去调用系统的TelephonyManager类的取数据.但是很多时候可能取不到卡的信息(例如双卡手机和 一些特殊卡),这样就区别不了运营商了.但是有时候我们的需求要 ...