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


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

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

  • 相关阅读:
    数据结构与算法的思维导图
    第九周知识总结
    第八周知识总结
    作业七:问卷调查

    图的基本概念及基本术语
    二叉树

    队列

  • 原文地址:https://www.cnblogs.com/wzy294250051/p/4787897.html
Copyright © 2020-2023  润新知