[Objective-C]第二天

【复习1st day内容】:

 1. OC在C的基础之上

    a. 增加了面向对象的语法

    b. 将C语言中复杂的繁琐的语法封装的更为简单.

 2. 更为简单.

    a. #import 指令

       同1个文件无论#import多少次. 最终都只会包含1次 不会出现重复包含的情况.

    b. NSLog函数.

       a. 自动换行.

       b. 会输出一些其他的调试信息.

    c. NSString

       a. OC字符串常量和C的字符串常量.

          字符串常量前面必须要加1个前缀@ 这才是OC的字符串.

           NSString只能存储OC字符串常量.

         NSString *str = @"jack";

    d. 数据类型.

       BOOL   YES  NO

       Boolean true false

       class 

       id

       nil

       SEL

       block

3.面向对象的语法

    1). 面向过程 面向对象.

    2). 面向对象的最大的优点.

    3). 类和对象

    4). 类和对象之间的关系.

    5). 设计类的三要素

        类名 特征 行为.

    6). 名词提炼法

 4. 类和对象

     1).定义类

        a. 位置: 

        b. 语法

           类的声明

@interface 类名 : NSObject
{
    属性
}
方法的声明
@end

           类的实现

@implementation 类名
方法的实现
@end

      2).方法的声明和实现.          

         a. 声明的位置: 在@interface的大括号的外面.

         b. 实现的位置: 在@implementation之中.

         c. 实现的语法: 将方法的声明拷贝到@implementation之中 去掉分号 追加大括号 将方法的实现代码写在大括号之中就可以了.

         无参数的方法的声明:

- (返回值类型)方法名;

         1个参数的方法的声明.

 - (返回值类型)方法名WithXXX:(参数类型)参数名;

         多个参数的方法.

 - (void)方法名WithXXX:(参数类型)参数名 andXXXX:(参数类型)参数名;

 5. 对象的创建.

        类名 *对象名 = [类名 new];

Person *p1 = [Person new];

        对象的特点: 1.对象拥有类中定义的所有的成员. 2. 对象中的成员可以直接访问.

 6. 访问对象.

 7. 同1个类可以创建N个对象 并且这N个对象毫无关系.

    在方法中直接访问属性 访问的就是当前对象的属性 

01-对象在内存中的存储

1. 内存中的五大区域.

     存储局部变量.

     程序员手动申请的字节空间 malloc calloc realloc函数.

     BSS段 存储未被初始化的全局变量 静态变量.

     数据段(常量区) 存储已被初始化的全局 静态变量 常量数据.

     代码段 存储代码. 存储程序的代码.

  2. 类加载.

     1). 在创建对象的时候 肯定是需要访问类的.

     2). 声明1个类的指针变量也会访问类的.

     在程序运行期间 当某个类第1次被访问到的时候. 会将这个类存储到内存中的代码段区域.这个过程叫做类加载.

     只有类在第1次被访问的时候,才会做类加载.

     一旦类被加载到代码段以后. 直到程序结束的时候才会被释放.

  3. 对象在内存中究竟是如何存储的.

     假设下面这个写在函数之中.

     Person *p1 = [Person new];

    1). Person *p1; 会在栈内存中申请1块空间. 在栈内存中声明1个Person类型的指针变量p1。

        p1是1个指针变量.  那么只能存储地址.

    2). [Person new]; 真正在内存中创建对象的其实是这句代码.

                  new做的事情

                  a. 内存中申请1块合适大小的空间.

                  b. 在这个空间中根据类的模板创建对象.

                     类模板中定义了什么属性.就把这些属性依次的声明在对象之中.

                     对象中还有另外1个属性 叫做isa 是1个指针. 指向对象所属的类在代码段中的地址.

                  c. 初始化对象的属性

                     如果属性的类型是基本数据类型 那么就赋值为0

                     如果属性的类型是C语言的指针类型 那么就赋值为NULL

                     如果属性的类型是OC的类指针类型9 那么就赋值为nil

                  d. 返回对象的地址.

    3). 注意

         a. 对象中只有属性,而没有方法. 自己类的属性外加1个isa指针指向代码段中的类.

         b. 如何访问对象的属性

            指针名->属性名;

            根据指针 找到指针指向的对象 再找到对象中的属性来访问.

         c. 如何调用方法.

            [指针名 方法名];

            先根据指针名找到对象,对象发现要调用方法 再根据对象的isa指针找到类.

            然后调用类里的方法.

  4. 为什么不把方法存储在对象之中?

     因为每1个对象的方法的代码实现都是一模一样的  没有必要为每1个对象都保存1个方法 这样的话就太浪费空间了.

     既然都一样 那么就只保持1份.

  5. 对象的属性的默认值.

     如果我们创建1个对象,没有为对象的属性赋值. 那么这个对象的属性是有值的.

     如果属性的类型是基本数据类型 默认值是0

     如果属性的类型是C指针类型 那么默认值是NULL

     如果属性的类型是OC指针类型  那么默认值是nil

02-nil与NULL

  1. NULL

     只能作为指针变量的值. 如果1个指针变量的值是NULL值代表. 代表这个指针不指向内存中的任何1块空间

     NULL其实等价于0  NULL其实是1个宏. 就是0

  2. nil

     只能作为指针变量的值. 代表这个指针变量不指向内存中的任何空间. 

     nil其实也等价于0 也是1个宏. 就是0.

     所以, NULL和nil其实是一样的 。

  3. 使用建议.

     虽然使用NULL的地方可以是nil 使用 nil的地方可以使用NULL 但是不建议大家去随便使用.

     C指针用NULL

int *p1 = NULL; //p1指针不指向内存中的任何1块空间.

     OC的类指针用nil

Person *p1 = nil; p1指针不指向任何对象.

  4. 如果1个类指针的值为nil 代表这个指针不指向任何对象.

Person *p1 = nil;

     那么这个时候 如果通过p1指针去访问p1指针指向的对象的属性 这个时候会运行报错.

     那么这个时候,如果通过p1指针去调用对象的方法 运行不会报错 但是方法不会执行 没有任何反应

03-多个指针指向同1个对象

  1. 同类型的指针变量之间是可以相互赋值的.

Person *p1 = [Person new];
Person *p2 = p1; 
//这是完全没有问题的. p1和p2的类型都是Person指针类型的.

    这是完全没有问题的. p1和p2的类型都是Person指针类型的.

    代表将p1的值赋值给p2 而p1的值是对象的地址 所以就把对象的地址赋值给了p2

    所以p1和p2指向了同1个对象.

    无论通过p1还是p2去修改对象,修改的都是同1个对象.

  2. 目前为止,只要你看到new 就说明新创建了1个对象.

04-分组导航标记

   分组导航标记:

   1). #pragma mark 分组名

       就会在导航条对应的位置显示1个标题.

   2). #pragma mark -

       就会在导航条对应的位置显示1条水平分隔线.

   3). #pragma mark - 分组名

       就会在导航条对应的位置先产生1条水平分割线.再显示标题.

05-方法与函数

  1. 我们之前在C中学习的函数,就叫做函数.

void test()
{
}

  2. 在OC类中写的方法.就叫做方法.

- (void)sayHi;

  3. 相同点:

     都是用来封装1段代码的. 将1段代码封装在其中, 表示1个相对独立的功能

     函数或者方法只要被调用.那么封装在其中的代码就会被自动执行.

  4. 不同点:

     1). 语法不同.

     2). 定义的位置不一样.

         OC方法的声明只能写在@interface的大括号的外面,实现只能写在@implementation之中.

         函数除了在函数的内部和@interface的大括号之中 其他的地方都是可以写.

         就算把函数写在类中 这个函数仍然不属于类 所以创建的对象中也没有这个函数.

         注意; 函数不要写到类中.虽然这样是可以的 但是你千万不要这么做 因为这么做是极度的不规范的.

     3). 调用的方式也不一样.

         函数可以直接调用.

         但是 方法必须要先创建对象 通过对象来调用.

     4). 方法数是属于类的. 有1个伐木累. 有个归属感.

         而函数是1个孤魂野鬼, 就是1个独立的.

06-都是你的错

  1. 最容易犯错

     1).  @interface是类的声明. @implementation是类的实现 他们之间不能相互嵌套

     2).  类必须要先声明然后再实现

     3).  类的声明和实现必须都要有 就算没有方法 类的实现也不必不可少的.

     4).  类的声明必须要放在使用类的前面.

          实现可以放在使用类的后面

     5).  声明类的时候 类的声明和实现必须要同时存在.

          特殊情况下可以只有实现 没有声明.

          虽然可以这样,但是我们平时在写类的时候千万不要这么写 因为这么写是极度不规范的 会被别人嘲笑的.

     6)  属性名一定要以下划线开头 这是规范. 否则后面的知识点你就对不上号.

         类名 每1个单词的首字母大写.

     7). 属性不允许声明的时候初始化

         在为类写1个属性的时候 不允许在声明属性的时候为属性赋值.

     8).  OC方法必须要创建对象通过对象名来调用

     9).   方法只有声明 没有实现

          a. 如果方法只有声明 没有实现  编译器会给1个警告  不会报错.

          b. 如果指针指向的对象 有方法的声明 而没有方法的实现 那么这个时候通过指针来调用这个方法

              在运行的时候  就会报错.

            unrecognized selector sent to instance 0x100420510

            只要你看到了这个错误.说明要么对象中根本就没有这个方法. 要么只有方法的声明而没有方法的实现.

07-多文件开发

  1. 所有的类都写在main.m这个源文件之中的.

     后果: 后期的维护就非常的不方便.也不利于团队开发

  2. 推荐的方式

     把1个类写在1个模块之中. 而1个模块至少包含两个文件.

     .h 头文件

         写的类声明 因为要用到Foundation框架中的类 NSObject 所以在这个头文件中要引入Foundation框架的头文件.

         然后将类的声明的部分写在.h文件中

     .m 实现文件

         先引入模块的头文件 这样才会有类的声明

         再写上类的实现.

     如果要用到类. 只需要引入这个了模块的头文件就可以直接使用了.

  3. 添加类模块的更简洁的方式

     NewFile->Cocoa Class->自动生成模块文件  .h  .m 

     自动的将类的声明和实现写好.

     填写的名称是决定模块文件的名称. 类名是可以自己再改的

     但是建议模块的文件名和模块中的类名保持一致.这样方便代码的管理.

  4. 当我们要使用这个类的时候,需要先将这个类的头文件先引进来.才可以使用.

08-对象与方法

  1. 对象和方法.

        对象作为方法的参数

        对象作为方法的返回值.

  2. 类的本质是我们自定义的1个数据类型. 因为对象在内存中的大小是由我们决定的.

     多写几个属性 对象就大一些 少写几个属性 对象占用的空间就小一些.

     什么是数据类型: 是在内存中开辟空间的1个模板.

  3. 既然类是1个数据类型,那么类就可以作为方法的参数.

     - (void)test:(Dog *)dog;

     这个是完全没有问题的.

  -------语法注意-------------

  1. 当对象作为方法的参数的时候. 参数应该怎么写 参数类型是类指针,

     - (void)test:(Dog *)dog;

  2. 调用方法的时候 如果方法的参数是1个对象.

     那么给实参的时候,实参要求也必须是1个符合要求的对象. 否则就会出问题.

  3. 当对象作为方法的参数传递的时候,是地址传递.

     所以 在方法内部通过形参去修改形参指向的对象的时候 会影响实参变量指向的对象的值.

  --------------

  对象也可以作为方法的返回值.

  1.什么时候方法的返回值是1个对象呢?

    当方法执行完毕之后,如果有1个对象方法的内部不知道如何处理.并且这个对象是调用者翘首以盼的.

    那么这个时候我们就应该将这个对象返回.

  2.如果方法的返回值是1个对象,那么返回值类型应该写 类指针.

09-上帝和人的故事

  有1个类:叫做上帝类.

      属性: 姓名 年龄. 性别.

      行为: 杀人.

  人类:

      属性: 姓名 年龄 性别 剩余的寿命.

      行为: 展示.

 

  

10-对象作为类的属性

 1. 对象作为类的属性.

     1). 类的属性代表什么?

         a.代表这类事物具有的共同的特征。

         b.代表类所拥有的东西.

         c: 设计类的时候.我们怎么知道这个类有哪些属性呢?

                分析这类事物拥有什么东西.

                 拥有的东西就可以作为这个类的属性.

         人有姓名、年龄、性别、身高、钱.

         空调类:品牌、颜色、大小、匹数.

     2). 类的方法代表什么?

         a.代表这类事物具有的行为.具有的功能.

         b.设计类的时候.我们如何知道这个类有哪些方法呢?

                 那么就分析这类事物具有哪些行为

                这个类事物具有哪些功能,会做什么?

         人: 走路 吃饭 睡觉 唱歌..

         空调: 制冷.制热.

  2. 有1个人类,还有1个狗类.

     人养了一条狗,人拥有1条狗.

     如何描述这个关系:人拥有1条狗.

     人拥有1条狗,那么就把狗作为人的1个属性.

  3. 对象完全可以作为另外1个类的属性.代表这个类拥有这个对象.

     A类拥有1个B对象,那么就将B对象作为A类的属性.

  4. 当A类作为B类的属性的时候.代表B拥有A

        在创建B类对象的时候, B类对象中的属性仅仅只是1个指针变量. 默认值是nil, 默认情况下并没有创建A对象.(如下图,dog类是p1的属性)

如果要正常使用的话,还要为B对象的A属性赋一个对象。

 

  5. 重点:

     1). 什么时候1个类可以作为另外1个类的属性.

         吊扇:

         扇叶:

     2). 属性的本质其实是1个变量.

     3). 如何访问对象的属性对象的成员.

11-猜拳游戏

1.猜拳游戏的流程

        1).玩家出拳.
        2).机器人出拳。
        3).裁判宣布比赛结果.


2.面向对象的重点在于找类。

      玩家类:


                属性:姓名、选择的拳头、得分。
                方法:出拳-→自行选择1个拳头来出。


      机器人类:


                属性:姓名、选择的拳头、得分。
                方法:出拳。-→随机出拳


       裁判类:


                属性:姓名
                方法:判断输赢并显示分数。


3.枚举或者结构体定义在什么地方。


        如果只是1个类要用。那么就定义在这个类的头文件中。
        如果多个类要用,那么就定义在单的头文中,谁要用谁就去引用。

4.如果在方法中调用当前对象的另外1个方法。

[sele 方法名];

[enum.h]

#ifndef enum_h
#define enum_h
typedef enum
{
 
    fistTypeJianDao = 1 ,
    fistTypeQuanTou = 2 ,
    fistTypeBu = 3
}fistType;
#endif /* enum_h */

 [Player.h]

#import <Foundation/Foundation.h>
#import "enum.h"

@interface Player : NSObject{
    @public
    NSString *_name;
    fistType _selectType;
    int _score;
    
}
-(void)showFist;
-(NSString*)fistTypeWithNumber:(int)number;
@end

[Player.m]

#import "Player.h"

@implementation Player
-(void)showFist
{
    //1.提示
    NSLog(@"亲爱的玩家🙅🏻‍♀️[%@],请选择你要出得拳头:1.剪刀 2.石头 3.布",_name);
    //2.接收
    int userSelect = 0;
    scanf("%d",&userSelect);
    //3.显示
    NSString* typeChar = NULL;
    while (typeChar == NULL) {
        typeChar = [self fistTypeWithNumber:userSelect];
        if (typeChar == NULL) {
            NSLog(@"输入错误,请重新输入");
            scanf("%d",&userSelect);
        }
        else{
            NSLog(@"玩家%@选择的拳头是:%@",_name,typeChar);
        }
    }

    //4.保存
    _selectType = userSelect;

}
-(NSString*)fistTypeWithNumber:(int)number{
    switch (number) {
        case 1:
            return @"剪刀";
        case 2:
            return @"石头";
        case 3:
            return @"布";
        default:
            return NULL;
    }
}
@end

[Robot.h]

#import <Foundation/Foundation.h>
#import "enum.h"
@interface RoBot : NSObject{
    @public
    NSString *_name;
    fistType _selectType;
    int _score;
}
-(void)showFist;
-(NSString*)fistTypeWithNumber:(int)number;
@end

[Robot.m]

#import "RoBot.h"
#import <stdlib.h>
#import "Player.h"

@implementation RoBot
- (void)showFist{
    int robotSelect = arc4random_uniform(3)+1;
    NSString * type = [self fistTypeWithNumber:robotSelect];
    NSLog(@"机器人%@出的拳头是:%@",_name,type);
    _selectType = robotSelect;
}
-(NSString*)fistTypeWithNumber:(int)number{
    switch (number) {
        case 1:
            return @"剪刀";
        case 2:
            return @"石头";
        case 3:
            return @"布";
        default:
            return NULL;
    }
}
@end

[judge.h]

#import <Foundation/Foundation.h>
#import "Player.h"
#import "RoBot.h"
@interface judge : NSObject
{   @public
    NSString *_name;
    
}
-(void)caiJueWithPlayer:(Player*)player andRobot:(RoBot*)robot;
@end

[judge.m]

#import "judge.h"

@implementation judge
-(void)caiJueWithPlayer:(Player*)player andRobot:(RoBot*)robot{
    fistType playerType = player->_selectType;
    fistType robotType = robot->_selectType;
    
//    (playerType == fistTypeJianDao && robotType == fistTypeBu)||
//    (playerType == fistTypeQuanTou && robotType == fistTypeJianDao)||
//    (playerType == fistTypeBu && robotType == fistTypeQuanTou)

    
    if(playerType-robotType == -2 || playerType -robotType == 1 )
    {
        NSLog(@"恭喜玩家[%@]取得了胜利!",player->_name);
        player->_score ++;
    }
    else if(playerType == robotType)
    {
        NSLog(@"[%@]&[%@]你们真是心有灵犀一点通啊!",
              player->_name,
              robot->_name);
    }
    else
    {
        NSLog(@"恭喜机器人[%@]取得了胜利!",robot->_name);
        robot->_score ++ ;
    }
    NSLog(@"----玩家:[%@]:[%d]--------机器人:[%@]:[%d]",
          player->_name,
          player->_score,
          robot->_name,
          robot->_score);
}
@end

main.m

 1.猜拳游戏的流程:
    1.玩家出拳
    2.机器人出拳
    3.裁判宣布比赛结果
 */

#import <Foundation/Foundation.h>
#import "enum.h"
#import "Player.h"
#import "RoBot.h"
#import "judge.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Player *p1 = [Player new];
        p1->_name = @"王大锤";
        RoBot *aGou = [RoBot new];
        aGou->_name =@"阿尔法🐶";
        judge *heiShao = [judge new];
        heiShao->_name =@"黑哨🔥";
        
        while (1) {
            [p1 showFist];
            [aGou showFist];
            [heiShao caiJueWithPlayer:p1 andRobot:aGou];
            NSLog(@"大爷,还要在玩一把吗?很刺激吆:y/n");
            char ans ='a';
            rewind(stdin);
            scanf("%c",&ans);
            if (ans!= 'y' ) {
                NSLog(@"欢迎下次再来玩哦~!");
                break;
            }
        }

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值