黑马程序员-OC的类和对象的初步认识

时间:2023-02-20 22:59:47
  • OC是面向对象的编程语言,如何创建和使用对象自然是重中之重,对象是怎么产生的呢?创建对象之前必须要有类,他就像要想盖大楼,必须要有图纸,这个图纸就类似于OC中的类

常用的关键字以及其他英文:

@interface / @end / @implementation / @public / NSLog(@"") / NSObject

-framework Foundation / Foundation / Foundation.h
  • 和函数一样,类也有声明实现,类的声明里应该包括对象的属性(成员变量)以及对象的行为(方法),其中方法的声明放在类的声明中,其实类的实现就是方法的实现,以下代码就是创建一个类以及通过类创建对象:
 1 //拷贝Foundation框架下的主头文件Foundation.h
 2 //import的作用类似include,区别就是:防止重复拷贝
 3 #import <Foundation/Foundation.h>
 4 
 5 //类的声明
 6 @interface Car : NSObject
 7 {
 8     @public // 让外部的指针能访问成员变量
 9     //实例变量(成员变量)
10     int wheels; // 轮胎
11     int speed; // 速度
12 }
13 
14 //对象方法的声明
15 - (void)run; // 不同于函数的声明: ‘-’ 表明是对象方法,以后还会遇到 ‘+’ ,小括号的作用是用来扩住数据类型
16 
17 @end // 类的声明结束标志
18 
19 // 类的实现
20 @implementation Car
21 
22 //方法的实现
23 - (void)run{
24     
25     NSLog(@"轮胎有%d个、速度为%d的车子跑起来了", wheels, speed);
26 }
27 
28 @end // 类的实现结束标志
29 
30 int main(){
31     //OC中想要执行一个行为(类的行为以及对象的行为),固定格式为:[行为执行者 行为名称],并且返回的是它在内存中地址
32     //new是类的一个行为,执行完的结果就是在内存中创建了相应的对象
33     Car *p = [Car new]; // 执行完这一句,内存中就有一个Car对象,并且指针p指向该对象
34     
35     p->wheels = 4;
36     p->speed = 150;
37     //因为p指向一个Car对象,所以[p run]执行的是一个对象run方法
38     [p run];
39     return 0;
40 }

想要成功编译链接这个.m文件,必须这么写:cc xxx.m -framework Foundation,其中xxx为文件名运行结果:黑马程序员-OC的类和对象的初步认识

上述代码的第33行是利用Car类创建了一个Car对象,如果我想再创建一个Car对象呢?依然还是相同的代码,只不过新的对象和之前的对象在内存中是出于不同的位置将上述代码的main函数改为:

 1 int main(){
 2     //OC中想要执行一个行为(类的行为以及对象的行为),固定格式为:[行为执行者 行为名称],并且返回的是它在内存中地址
 3     //new是类的一个行为,执行完的结果就是在内存中创建了相应的对象
 4     Car *p = [Car new]; // 执行完这一句,内存中就有一个Car对象,并且指针p指向该对象
 5     Car *p1 = [Car new];
 6     
 7     p->wheels = 4;
 8     p->speed = 150;
 9     
10     p1->speed = 200;
11     p1->wheels = 3;
12     //因为p指向一个Car对象,所以[p run]执行的是一个对象run方法
13     [p run];
14     [p1 run];
15     
16     return 0;
17 }

该程序的运行结果为黑马程序员-OC的类和对象的初步认识

  • 对于第一个程序中的第38行代码系统式如何运行的呢?当程序第一次使用类的时候,内存中会分配一定的空间给类,并且只会加载一次,并且对象的方法会放在类中,并且每次通过类创建一个对象,这个对象中会有一个isa指针指向该类,一旦调用对象的方法(比如这一题的run方法)它会通过isa指针找到类中的对象方法
  • 注意事项:
  1. 类的声明里不能嵌套其他类的声明或者嵌套自己类的实现。代码如下
     1 //错误代码示范:嵌套类的声明
     2 @interface Car :NSObject
     3 
     4 ...
     5 
     6 @interface Person :NSObject
     7 
     8 ...
     9 
    10 @end
    11 
    12 @end
    13 
    14 //错误代码示范:嵌套类的实现
    15 @interface Car :NSObject
    16 
    17 ...
    18 
    19 @implementation Car
    20 
    21 ...
    22 
    23 @end
    24 
    25 @end

     

  2. 类的所有实例变量要用大括号括起来,对象方法的声明不能放在发括号里,要拿出来。并且不能人为初始化,因为系统会自动初始化所有实例变量(比如int、float等类型初始化为0,指针类型的初始化为nil(类似于C语言中的NULL))
    1 //错误代码示范
    2 @interface Car :NSObject
    3 
    4 {
    5     int speed = 100;
    6     char *name = "MJ";
    7 }
    8 
    9 @end

     

  3. 关于实例变量的使用:实例变量是对象所独有的,也就是说只有创建了对象才能使用实例变量,并且要想指针访问实例变量,必须在实例变量前加上关键字@public
     1 //错误代码示范
     2 @interface Car :NSObject
     3 
     4 {
     5     int speed;
     6 
     7 }
     8 
     9 ...
    10 
    11 @end
    12 
    13 @implementation Car
    14 
    15 ...
    16 
    17 @end
    18 
    19 int main(){
    20     
    21     speed = 90; // 没有创建对象之前是不能使用实例变量的,即使实例变量前面加了@public
    22     ...
    23 }

     

  4. 类的声明和实现与main函数的位置问题:和C语言中函数的声明和定义一样,类的声明必须放在main函数前面,类的实现可以放在main函数的后面,不同的是,类的声明不不能省略的
  5. 另外要注意对象方法的声明与之前学过的函数声明的不同之处:对象方法的标志'-'小括号要扩住数据类型例如
    1 - (void)run;
    2 
    3 - (int)eat;

     

  • 下面将创建一个Person类以及Dog类并且让Person类里有一个Dog实例变量
      1 #import<Foundation/Foundation.h>
      2 
      3 //性别枚举
      4 typedef enum{
      5     SexMan, //
      6     SexWoman //
      7 } Sex;
      8 
      9 //颜色枚举
     10 typedef enum{
     11     ColorBlack, // 黑色
     12     ColorRed, // 红色
     13     ColorYellow //黄色
     14 } Color;
     15 
     16 // 生日结构体
     17 typedef struct{
     18     int year; //
     19     int month; //
     20     int day; //
     21 } Date;
     22 
     23 //Dog类的声明
     24 @interface Dog : NSObject
     25 {
     26     @public
     27     int weight;
     28     Color curColor;
     29 }
     30 
     31 - (void)run; // run方法声明
     32 - (void)eat; // eat方法声明
     33 @end
     34 
     35 //Dog类的实现
     36 @implementation Dog
     37 
     38 - (void)run{
     39     weight -= 1;
     40     NSLog(@"毛色为%d的狗体重减少为:%d", curColor, weight);
     41 }
     42 
     43 - (void)eat{
     44     weight += 1;
     45     NSLog(@"毛色为%d的狗体重增加为:%d", curColor, weight);
     46 }
     47 @end
     48 
     49 // Person类声明
     50 @interface Person : NSObject
     51 {
     52     @public
     53     int age; // 年龄
     54     int weight; // 体重
     55     Sex sex; // 性别
     56     Date birthday; // 生日
     57     Color favColor; // 最喜欢的颜色
     58     Dog *dog;
     59     
     60 }
     61 
     62 - (void)run; // run方法声明
     63 - (void)eat; // eat方法声明
     64 - (void)printf; // printf方法声明
     65 - (void)playWithDog;
     66 - (void)feedDog;
     67 @end
     68 
     69 //Person类实现
     70 @implementation Person
     71 
     72 - (void)run{
     73     weight -= 1;
     74     NSLog(@"年龄为%d的人体重减少为:%d", age, weight);
     75 }
     76 
     77 - (void)eat{
     78     weight += 1;
     79     NSLog(@"年龄为%d的人体重增加为:%d", age, weight);
     80 }
     81 
     82 - (void)printf{
     83     NSLog(@"体重为%d-年龄为%d-性别为%d-最爱的颜色为%d-生日为%d/%d/%d", weight, age, sex, favColor, birthday.year, birthday.month, birthday.day);
     84 }
     85 
     86 - (void)playWithDog{
     87     [dog run];
     88 }
     89 
     90 - (void)feedDog{
     91     [dog eat];
     92 }
     93 @end
     94 
     95 int main(){
     96     //创建Person对象
     97     Person *p = [Person new];
     98     
     99     //初始化Person对象实例变量
    100     p->age = 24;
    101     p->weight = 60;
    102     p->sex = SexMan;
    103     p->favColor = ColorYellow;
    104     Date d = {2000,4,5}; // 初始化结构体Date变量d
    105     p->birthday = d;
    106     
    107     //创建Dog对象
    108     Dog *dog = [Dog new];
    109     p->dog = dog;
    110     
    111     //初始化Dog对象实例变量
    112     dog->weight = 15;
    113     dog->curColor = ColorRed;
    114     
    115     [p playWithDog]; // 调用Person对象的playWithDog方法
    116     [p playWithDog];
    117     [p playWithDog];
    118     [p feedDog];
    119     
    120     [p run]; // 调用Person类的run方法
    121     [p run];
    122     [p run];
    123     
    124     [p eat]; // 调用Person类的eat方法
    125     [p printf]; // 调用Person类的printf方法
    126     
    127     return 0;
    128     
    129 }

    (也不知道代码能不能想C那样分成多个文件)这样在一个.m文件写下去的话,肯定会让人崩溃的。在写这一段代码中我犯了如下错误:

  1. @public漏写
  2. 将Dog类的声明写在了Person类声明的后面,这样会导致编译链接的时候会警告Dog *dog没有定义(估计等学到了多文件开发的时候这个问题就能避免了)
  3. 漏写了上述代码的第109行,这样会导致Person对象中的dog成员变量指向nil(空),进一步导致第115-118行的所有代码无效