OC语法之-类和对象

  1. 完整的描述一个类:
    • 完整地写一个函数:函数的声明和定义(实现)
    • 完整地写一个类:类的声明和实现
  2. 类名的命名规范:有意义、驼峰标识、首字母大写
  3. 类名\属性的命名规则:标示符的规则
  4. 类的声明:
    • 作用:声明对象的属性、行为
    • 必须:NSObject
      • 作用:让Car类具备创建对象的能力
    • 成员变量:
      • @interface的大括号{}中声明的变量:wheels、speed
      • @interface的大括号和函数的大括号是不一样的,他是用来声明对象属性(实例变量\成员变量,默认会初始化为0
      • @public可以让Car对象的wheels和speed属性被外界访问
    • 行为:
      • 也叫方法,方法名、参数、返回值(声明、实现)
      • 只要是OC对象的方法,必须以减号 - 开头
      • OC方法中任何数据类型都必须用小括号()扩住
      • OC方法中的小括号():括住数据类型
      • 注意跟C语言
  5. 类的实现:
    • 作用:
      • 用来实现@inteface中声明的行为(方法)
      • 方法的实现(说清楚方法里面有什么代码)
     // 因为使用了NSObject
     #import <Foundation/Foundation.h>
        
     // 1.类的声明
     // 声明对象的属性、行为
     // : NSObject 目的是:让Car这个类具备创建对象的能力
     @interface Car : NSObject
     {// 用来声明对象属性(实例变量\成员变量,默认会初始化为0)
         // @public可以让外部的指针间接访问对象内部的成员变量
         @public
         int wheels; // 轮胎个数
         int speed; // 时速(xxkm/h)
     }
        
     // 方法(行为):方法名、参数、返回值(声明、实现)
     // 只要是OC对象的方法,必须以减号 - 开头
     // OC方法中任何数据类型都必须用小括号()扩住
     // OC方法中的小括号():括住数据类型
     - (void)run;
        
     @end
        
     // 2.类的实现
     // 用来实现@inteface中声明的方法
     @implementation Car
        
     // 方法的实现(说清楚方法里面有什么代码)
     - (void)run {
         NSLog(@"车子跑起来了");
     }
     @end
    

创建对象

  1. 用一个类来创建对象
    • 在OC中,想执行一些行为,就写上一个中括号[行为执行者 行为名称]
    • [Car new];执行了Car这个类的new行为来创建新对象
    • OC中只能用指针来操纵对象
    • [Car new]每次都会创建出一个新对象,并且会返回新对象本身(新对象的地址)
    • 定义一个指针变量p,p将来指向的是Car类型的对象
  2. 设置一个对象的属性
    1. 跟用指向结构体的指针访问结构体属性一样,用-> ,代码如下:
     int main() {
         // 在OC中,想执行一些行为,就写上一个中括号[行为执行者 行为名称]
         // 利用类来创建对象
         // 执行了Car这个类的new行为来创建新对象
            
         // 定义了一个指针变量p,p将来指向的是Car类型的对象
         // [Car new]每次都会创建出一个新对象,并且会返回新对象本身(新对象的地址)
         Car *p = [Car new];
         //外部的指针间接访问对象内部的成员变量,必须有@public修饰
         // 给p所指向对象的wheels属性赋值
         p->wheels = 4;
         p->speed = 250;
         // 给p所指向对象发送一条run消息
         [p run];
            
         Car *p2 = [Car new];
         p2->wheels = 5;
         p2->speed = 300;
         [p2 run];
         NSLog(@"车子有%d个轮子,时速位:%dkm/h", p->wheels, p2->speed);
            
         return 0;
     }
    

    注意:以上代码都在一个.m文件中

方法与成员变量

  1. 对象方法中直接可以拿到当前类的成员变量,来使用
    • 原理:当对象调用方法时,方法中使用到成员变量时,就会到方法调用者这个对象中找相应的成员变量
     #import <Foundation/Foundation.h>
     @interface Person : NSObject
     {
         @public
         int age;
         double weight;
     }
     - (void)walk;
        
     @end
        
     // 2.类的实现
     @implementation Person
     // 实现@interface中声明的方法,可以直接使用成员变量
     - (void)walk
     {
         NSLog(@"%d岁、%f公斤的人走了一段路", age, weight);
     }
     @end
        
     int main()
     {
         Person *p2 = [Person new];
         p2->age = 30;
         p2->weight = 60.0;
         [p2 walk];
         return 0;
     }
    

对象的简单内存分析

  1. 类在内存中也会占据存储空间
  2. 当你第一次使用类的时候,系统就会给这个类分配内存,把这个类加载进内存
  3. 即你第一次使用类创建对象时,它是先把这个类加载进内存,然后创建对象,并且整个程序运行中,类只会加载一次
  4. 整个程序中类只占用一份存储空间,同一种类创建多个对象,就会分配多个对象的内存.
  5. 类里面只存放方法列表(类方法和对象方法)
  6. 每个对象内部都有一个isa指针,指向它所对应的类
  7. 因此,当你用一个类创建很多对象,并且用这些对象调用方法时,所有的对象都公用一个方法
  8. 成员变量是每个对象独有的,比如:对象p1的成员变量age是10,对象p2的成员变量age是20;
  9. 调用方法做了什么事情?[p eat];
    • 给指针表变量p(对象)发送一条eat消息
    • 对象p会根据isa指针找到对应的类
    • 在类中找到相应的方法调用对应的代码
    • 代码中用到对象的age跟weight,就回访问当前对象的age跟weight

对象与函数参数

  1. 对象成员变量作为函数参数
  2. 指向对象的指针作为函数参数
    • 修改指向指向对象的成员
    • 修改指针的指向
     #import <Foundation/Foundation.h>
     @interface Car : NSObject
     {// 成员变量
         @public
         int wheels;
         int speed;
     }
     - (void)run;
     @end
        
     @implementation Car
     - (void)run
     {
         NSLog(@"%d个轮子,速度为%dkm/h的车子跑起来", wheels, speed);
     }
     @end
        
     void test(int w, int s)
     {
         w = 20;
         s = 200;
     }
     void test1(Car *newC)
     {
         newC->wheels = 5;
     }
        
     void test2(Car *newC)
     {
         //对象2
         Car *c2 = [Car new];
         c2->wheels = 5;
         c2->speed = 300;
            
         newC = c2;
         newC->wheels = 6;
     }
        
     int main()
     {
         //对象1
         Car *c = [Car new];
         c->wheels = 4;
         c->speed = 250;
         //值传递,不会改变
         test(c->wheels, c->speed);
         //指针传递会改变
         test1(c);
         //此时的c指针仍然指向对象1,只是newC这个指针指向了对象2
         //结果仍不变
         test2(c);
         [c run];
         return 0;
     }
    

常见错误

  1. 只有类的声明,没有类的实现
  2. 漏了@end
  3. @interface和@implementation嵌套
  4. 两个类的声明嵌套
  5. 成员变量没有写在括号里面
  6. 方法的声明写在了大括号里面
  7. 成员变量不能在{}中进行初始化、不能被直接拿出去访问
  8. 方法不能当做函数一样调用
  9. 成员变量\方法不能用static等关键字修饰,别跟C语言混在一起
  10. 类的实现可以写在main函数的后面,主要在类的声明后面就行了

OC方法跟函数的区别

  1. OC对象方法方法:
    1. 对象方法都是以减号 - 开头
    2. OC方法只能声明在@interface和@end之间,只能实现在@implementation和@end之间。也就是说OC方法不能独立于类存在
    3. 对象方法只能由对象来调用
    4. 对象方法归类所有
    5. 低级错误:方法有声明,但是实现的时候写成了函数
  2. C函数
    1. 函数能写在文件中的任意位置(@interface和@end之间除外),函数归文件所有
    2. C函数不属于类,跟类没有联系,C函数只归定义函数的文件所有
    3. 函数调用不依赖于对象
    4. C函数不能访问OC对象的成员
  3. OC的方法注意
    1. 方法只有声明,没有实现(经典错误)
    2. 方法没有声明,只有实现(编译器警告,但是能调用,OC的弱语法)
    3. 编译的时候:访问没有的成员变量直接报错,访问没有的方法,只是警告
     #import <Foundation/Foundation.h>
     @interface Car : NSObject
     {// 成员变量\实例变量
         //int wheels = 4; 不允许在这里初始化
         //static int wheels; 不能随便将成员变量当做C语言中的变量来使用
         @public
         int wheels;
     }
        
     - (void)run;
     - (void)fly;
     @end
        
     int main() {
         // wheels = 10;
            
         Car *c = [Car new];
         c->wheels = 4;
            
         //oc方法调用
         //方法调用依赖于对象
         //run();错误
         [c run];
            
         //函数调用
         void test2();
         //调用不依赖于对象
         test2();
            
         return 0;
     }
        
     @implementation Car
        
     - (void) fly {
     }
        
     /*
      //函数不可以访问成员变量
     void test2() {
         NSLog(@"调用了test2函数-%d", wheels);
     }*/
     //函数可以写在任何地方
     void test() {
         NSLog(@"调用了test函数");
     }
     //对象方法方法
     - (void)run{
         test();
         NSLog(@"%d个轮子的车跑起来了", wheels);
     }
     @end
    

@implementation

  1. 没有@interface,只有@implementation,也是能成功定义一个类的(仅仅在编译时会有警告而已),就像C语言的函数,可以没有函数的声明,只要把函数定义写在调用者的前面就行了
  2. @implementation中不能重复声明和@interface一样的成员变量(也就是说,如果interface中声明了一个成员变量,那么@implementation中不能重复)
  3. 声明成员变量不仅可以在@interface中的{}中,也可以在@implementation中的{}中
    代码举例:
#import <Foundation/Foundation.h>
//在implementation也可以声明成员变量
@implementation Car : NSObject
{
@public
    int wheels; // 多少个轮子
    int speed; // 时速
}
- (void) run {
    NSLog(@"%i个轮子,%i时速的车子跑起来了", wheels, speed);
}
@end

int main(){
    Car *p = [Car new];
    p->wheels = 4;
    p->speed = 100;
    [p run];
    return 0;
}

OC方法

//无返回值,无参数  
-(void)run;
//无返回值有参数  
-(void)run:(int)speed;
//有返回值无参数  
-(int)run;
//有返回值有参数  
-(int)run:(int)speed;
//有返回值多参   
- (int)sumWithNum1:(int)num1 andNum2:(int)num2;`

  1. 方法声明中的小括号”()”仅仅是用来括住数据类型
  2. OC方法中,一个参数对应一个冒号
  3. 冒号也是方法名的一部分
  4. 每个参数之间一定要用空格隔开
  5. 一个类中不允许有同名的方法

方法的声明

  1. 方法的声明不一定必须要有,方法的实现一定要有.
  2. 如果一个方法,只在当前类中使用,而不再外部使用时,可以不用声明方法
  3. 如果一个方法会在外部(main函数或者其他类,非当前类)使用,一定要有方法的声明,否则:1.虽然不会报错,但会警告 2.写代码时xcode不会提示.
    代码举例:
#import <Foundation/Foundation.h>
@interface Car : NSObject
//在外部会使用,要声明
- (void)run;

@end

@implementation Car

- (void)run {
    [self test];
    NSLog(@"车子跑起来了");
}
//不在外部使用,不用声明
-(void)test {
       NSLog(@"我仅仅在当前类内部使用");
}
@end

int main() {
    Car *p = [Car new];
    [p run];
    return 0;
}

匿名对象

  1. 所谓的匿名对象就是创建一个对象不用指针指着他了
  2. 属性访问 [Car new]->speed = 200;
  3. 方法调用 [[Car new] run];
  4. 注意: 这两个[Car new]可不是同一个对象
Table of Contents