RE0_OC_1

参考资料:

blog.csdn.net/m0_57836225...

(1)类与对象

Objective-C 的类: 类包含了两个部分:定义(interface)与实现(implementation)。定义(interface)部分包含了类声明和实例变量的定义,以及类相关的方法。实现(implementation)部分包含了类方法的实际代码。

objectivec 复制代码
#import <Foundation/Foundation.h>
//类接口声明
@interface Animal : NSObject 
@property (nonatomic, strong) NSString *name; //属性(类的特征)
- (instancetype)initWithName:(NSString *)name;  //单个参数的方法声明
- (NSString *)introduce:(NSString *)name :(int)age :(NSString *)gender; //多个参数的方法声明
- (void)makeSound;  //实例方法(无返回值无传参的方法声明)  (类的功能)
+ (void)wolfing;  //类方法
@end
arduino 复制代码
//预处理指令
#import <Foundation/Foundation.h>

#import:OC特有的头文件引入指令,eg:#import <Foundation/Foundation.h>

<Foundation/Foundation.h>: Cocoa 和 Cocoa Touch框架的核心组件,有点类似于C语言的studio.h,包含NSObject、NSString等基础类,为IOS开发提供运行环境,以及需要遵从的协议;

less 复制代码
//类接口声明
@interface Animal : NSObject

@interface :类/接口的声明符,结尾需使用 @end;(类名遵循大驼峰命名规范)

objectivec 复制代码
//属性声明
@property (nonatomic, strong) NSString *name;

@property:属性声明方法,可以自动生成getter和setter

nonatomic:OC在定义时有原子属性(atomic)和非原子属性(nonatomic)两种属性、atomic是线程安全,需要消耗大量的资源;nonatomic是非线程安全,适合内存较小的移动设备;因此在IOS APP开发时,建议所有的属性都适用nonatomic,避免多线程抢占资源,将加锁、资源抢夺的逻辑交给服务端处理,减轻客户端的压力;

strong :一种属性声明,表示指向并拥有该对象,表示浅拷贝,多个指针指向同一个地址;

与之对应的常用属性声明是copy,表示深拷贝,copy的属性会在内存中拷贝一份新的对象,指向新的地址;

objectivec 复制代码
//方法声明
- (instancetype)initWithName:(NSString *)name;
- (void)makeSound;

--- :实例方法标识符,类方法用 + 标识

instancetype:返回类型声明,表示不确定类型,运行时才能确定,即调用该方法的类实例对象指针;因为不确定性,因此不能作为对象的定义类型,只能用户成员方法返回类型;与之相关的是id类型,也是未知类型,但是是确定的(确定未知),因此可以用作定义对象类型,eg:id Animal;

initWithName: 方法名(遵循小驼峰命名规范)

**(NSString )* :参数类型声明(中间有一个空格)、明确参数为字符串指针,NSString表示字符串类型;

(void) :无返回值方法声明

@end:协议与内存管理

objectivec 复制代码
//类接口实现
@implementation Animal;
- (instancetype)initWithName:(NSString *)name{
    self = [super init]; 
    if(self){
        _name = name;
    }
    return self;
}
- (void)makeSound{
  NSLog(@"I am %@,I can wolf",slef.name)
}
+ (void)wolfing{
  NSLog(@"I can wolfing");
}
@end    //必须以end闭合
objectivec 复制代码
//实现实例方法
- (instancetype)initWithName:(NSString *)name{
  self = [super init];  //确保父类初始化完毕后再初始化子类
  if(self){ // 确认self初始化成功,不为nil
    _name = name //使用_name的方式访问变量来设置属性值,避免不必要的setter;
  }
  return self
}
//多传参方法实现
- (NSString *)introduce:(NSString *)name :(int)age :(NSString *)gender{
    NSString *result = [NSString stringWithFormat:@"my name is %@,i am %d years old, i am %@",name,age,gender];
    NSLog(@"%@",result);
    return result;
}
- (void)makeSound{
  NSLog(@"I am %@,I can wolf",slef.name)
}
//实现类方法
+ (void)wolfing{
  NSLog(@"I can wolfing");
}

self = [super init] :确保父类初始化完毕后再初始化子类

已经声明和实现了一个接口,那么应该如何使用它?

csharp 复制代码
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Animal *animal = [[Animal alloc] initWithName:@"gggg"]; 
        NSLog(@"init name is %@",animal.name);  //因为你初始化的时候给了name属性一个默认值,因此这个地方打印出来是gggg
        animal.name = @"Dog"; //你也可以重写这个属性的值,打印出来就是你重写的值
        [animal makeSound]; //实例化方法需要实例化对象进行调用
        [Animal wolfing]; //类方法,可以不经过实例化,直接被类调用;
        [animal introduce:@"小花" :9 :@"男"];
    }
    return 0;
}

@autoreleasepool:自动释放池,在该释放池内创建的对象在被销毁时会被自动释放;

ini 复制代码
Animal *animal = [[Animal alloc] initWithName:@"gggg"]; 

上述代码是为Animal类创建了一个实例,名称叫做animal,[Animal alloc]的作用时调用 alloc 方法为 Animal 类分配内存。alloc 方法会返回一个指向 Animal 对象的指针,但此时对象还未初始化。因此后续需要init类进行初始化; 一般情况下,如果不传参数的话,我们用init方法这设置对象的初始状态即可,例如将属性设置为默认值。不会为属性提供一个初始值;

ini 复制代码
Animal *animal = [[Animal alloc] init]
//在oc2.0中,如果不需要传参,可以直接使用new 方法
Animal *animal = [Animal new]

但,我们在类声明时声明了一个initWithName方法,即

objectivec 复制代码
- (instancetype)initWithName:(NSString *)name;

这个方法就要求你实现的时候,必须也实现这个方法,初始化一个name 因此,Animal *animal = [[Animal alloc] initWithName:@"gggg"]的作用就是在初始化时为animal实例添加了一个name属性,值为gggg

(2)继承

我们可以把Animal当成父类,然后我们继续创建一个Dog的子类,并继承父类,则代码变成了:

objectivec 复制代码
#import <Foundation/Foundation.h>
​
//创建父类接口
@interface Animal : NSObject;   //继承自根Object
@property (nonatomic, strong) NSString *name;   //属性声明
- (instancetype)initWithName:(NSString *)name;  //方法声明
- (void)makeSound;  //实例方法声明,用-修饰
+ (void)wolfing; //类方法声明,用+修饰
@end
​
//父类接口实现
@implementation Animal;
// 实例化方法
- (instancetype)initWithName:(NSString *)name{
    self = [super init]; //防御性措施,确保父类初始化成功后再初始化子类
    //检查self是否为nil
    if(self){
        _name = name;
        // 通过在方法内部使用下划线前缀(如_name = name;),直接访问实例变量来设置属性值。
        // 这是因为在Objective-C中,直接使用属性名进行赋值会自动调用属性的setter方法,
        // 这在某些情况下(如懒加载属性)是有用的,但在初始化时直接使用实例变量可以避免不必要的setter调用开销。
    }
    return self;
}
- (void)makeSound{
    NSLog(@"I am  %@,I can wolf",self.name);
}
+ (void)wolfing{
    NSLog(@"I can wolfing");
}
@end
​
//声明子类接口
@interface Dog : Animal;
@property (nonatomic,strong)NSString *leg;
-(void)makeRun;
@end
​
//子类接口实现
@implementation Dog;
- (void)makeRun{
    NSLog(@"I can RUN");
}
@end
​
//程序入口
int main(int argc, const char * argv[]) {
    //自动释放池
    @autoreleasepool {
        Animal *animal = [[Animal alloc] initWithName:@"gggg"]; //创建一个类的实例
        NSLog(@"init name is %@",animal.name);
        animal.name = @"Dog";  //添加属性,字符串前
        [animal makeSound];     //执行实例方法
        [Animal wolfing];     //类的方法不用实例化,可被类直接调用
        
        // 子类可直接调用父类的属性和方法,包括实例方法和类方法
        Dog *dog = [[Dog alloc] init];
        dog.name= @"petty";
        dog
        [dog makeRun];  //调用自己的实例方法
        [dog makeSound];    //调用父类的实例方法
        [Dog wolfing];  //调用父类的类方法
    }
    return 0;
}
​

(3)对象的属性

对象的属性:

objectivec 复制代码
@interface Dog : NSObject {
    NSString *age;
    int _a;
    float _b;
}
@end

一般情况下,对象的属性是不是允许被外部访问的,即:

csharp 复制代码
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Dog *dog2 = [[Poodle alloc] init];
        dog2->_a = 2; //当前情况下是无法给对象的属性进行赋值的
    }
    return 0;
}

若要在外部访问对象中的属性,则需要@public关键字进行修饰;

objectivec 复制代码
@interface Dog : NSObject {
    @public
    NSString *age;
    int _a;
    float _b;
}
@end

访问的语法:

ini 复制代码
Dog *dog1 = [[Dog alloc] init]  //类的实例化 oc 1.0写法
Dog *dog1 = [Dog new];  //类的实例化 oc 2.0写法(常用)
​
dog1->_a = 2;   //访问并修改类的属性值,写法一(常用)
(*dog1)._a = 4; //访问并修改类的属性值,写法二

(4)方法的实现可以直接访问对象所声明的属性

例如,我们有如下的Person类的声明,其中包含了一些方法:

objectivec 复制代码
@interface Person : NSObject{
    NSString *_name;
    int _age;
    NSString *_gender;
}
- (void)run:(NSString *)name;
@end
​
​
@implementation Person;
- (void)run:(NSString *)name{
    _age = 10;  
    NSLog(@"i am %@,i am runing,my age is %d",name,_age);
}
​
@end

在上述代码中,可以在方法的实现中,直接访问对象的属性,不用实例化,而且不要求对象的属性使用@public进行修饰;

(5)分组导航标记

当一个文件中有很多类和类的实现时,不方便查找;可以为类和类的实现加上中文导航,方便快速查找;

1、第一种导航方法:在导航条中添加一个标题

arduino 复制代码
#pragma mark 分组名

2、第二种导航方法:在导航条中添加一条横线

arduino 复制代码
#pragma mark -

3、第三种导航方法,可直接结合水平线和标题

arduino 复制代码
#pragma mark - 猫猫类

(6)类指针作为方法的参数

类,本质上来讲是我们自定义的一个数据类型,因此是可以作为方法的参数的;

首先声明一个Dog类:

objectivec 复制代码
@interface Dog : NSObject{
    NSString *_name;
}
-(void)bark;
@end
​
@implementation Dog
- (void)bark{
    NSLog(@"狗会叫");
}
@end

然后声明一个Person类:

less 复制代码
@interface Person : NSObject{
    @public
    NSString *_name;
    int age;
}
-(void) eat;
-(void) testDog:(Dog *)dog1;
@end
  
@implementation Person
-(void)eat{
    NSLog(@"我是人,我会吃饭");
}
-(void)testDog:(Dog *)dog1{
    [dog1 bark];
}
@end

在Person类中,我们声明了一个方法testDog,这个方法需要传入一个Dog类指针作为参数,然后这个testDog的实现是调用了Dog类指针中的bark方法;

因此在使用时,我们就可以通过实例话Person指针,并调用testDog方法,同时传入Dog类指针作为参数;且只能传入Dog类,因为声明的是Dog类;

csharp 复制代码
int main(int argc, const char * argv[]){
    Person *p1 = [Person new];
    Dog *dog1 = [Dog new];
    [p1 testDog:dog1];  //传入一个类指针作为方法的参数
}

而且当对象作为方法的参数时,是地址传递;

如:我们在Person类的实现中修改了狗的名称:

scss 复制代码
@implementation Person
-(void)eat{
    NSLog(@"我是人,我会吃饭");
}
-(void)testDog:(Dog *)dog1{
    dog1->_name = @"大黄";
    [dog1 bark];
}
@end

然后在main中调用的时候也修改了狗的名称;

ini 复制代码
int main(int argc, const char * argv[]){
    Person *p1 = [Person new];
    Dog *dog1 = [Dog new];
    dog1->_name = @"旺财";
    [p1 testDog:dog1];  //传入一个类指针作为方法的参数
    NSLog(@"狗的名字是:%@",dog1->_name);
}

那么此时狗的名称是:大黄;因为虽然我们先将dog的_name属性修改为了旺财,但是,我们又执行了p1的testDog方法,在这个方法中,又将 _name属性改为了大黄;这就是因为传入的Dog *指针是地址,大家都指向同一个对象,因此改的都是同一个属性;

(7)上帝杀人示例(对象作为方法的参数)

Gog类:

objectivec 复制代码
@interface God : NSObject{
    @public
    NSString *_name;
    int _age;
    int _leftlife;
    Gender _gender;
}
-(void)killWithPerson:(Person *)person;
@end
​
@implementation God
-(void)killWithPerson:(Person *)person{
    NSLog(@"我是%@,请喝下这杯毒药,凡人......",_name);
    NSLog(@"要带走的人是:%@,他今年%d岁,性别为:%u,剩余生命为:%d",person->_name,person->_age,person->_gender,person->_leftLife);
    person->_leftLife = 0;
    NSLog(@"%@已经被带走了,他的剩余生命为%d",person->_name,person->_leftLife);
}
@end

Person类:

objectivec 复制代码
@interface Person : NSObject{
    @public
    NSString *_name;
    int _age;
    int _leftLife;
    Gender _gender;
}
@end
​
@implementation Person
​
@end

main函数:

ini 复制代码
int main(int argc, const char * argv[]){
    God *god = [God new];
    Person *p1 = [Person new];
    god->_name = @"耶稣";
    god->_age = 9999;
    god->_leftlife = 9999;
    god->_gender = GenderMale;
    
    p1->_name = @"小东";
    p1->_age = 30;
    p1->_gender = GenderFeMale;
    p1->_leftLife=10;
    
    [god killWithPerson:p1];
}

(8)对象作为方法的返回值

返回值是一个对象,那么返回值类型应该是类指针;

按照上帝的那个例子来讲:为上帝新增一个造人的方法(带参和不带参)

objectivec 复制代码
@interface God : NSObject{
    @public
    NSString *_name;
    int _age;
    int _leftlife;
    Gender _gender;
}
-(void)killWithPerson:(Person *)person;
-(Person *)makePerson;  //每次都造一样的属性
-(Person *)makePersonWithName:(NSString *)name andGender:(Gender)gender andAge:(int)age andleftLife:(int)leftLife;  //有多个参数传参,可以自定义属性
​
@end
ini 复制代码
@implementation God
-(void)killWithPerson:(Person *)person{
    NSLog(@"我是%@,请喝下这杯毒药,凡人......",_name);
    NSLog(@"要带走的人是:%@,他今年%d岁,性别为:%u,剩余生命为:%d",person->_name,person->_age,person->_gender,person->_leftLife);
    person->_leftLife = 0;
    NSLog(@"%@已经被带走了,他的剩余生命为%d",person->_name,person->_leftLife);
}
-(Person *)makePerson{
    Person *p1 = [Person new];  //  创建要返回的对象实例
    p1->_name =@"亚当";
    p1->_age = 20;
    p1->_gender = GenderMale;
    p1->_leftLife = 20
    return p1;
}
-(Person *)makePersonWithName:(NSString *)name andGender:(Gender)gender andAge:(int)age andleftLife:(int)leftLife{
    Person *p1  = [Person new];
    p1->_name = name;
    p1->_age = age;
    p1->_gender = gender;
    p1->_leftLife = leftLife;
    
    return p1;
}
@end

在Person类中新增一个展示的方法:

objectivec 复制代码
@interface Person : NSObject{
    @public
    NSString *_name;
    int _age;
    int _leftLife;
    Gender _gender;
}
-(void)show;
@end
  
@implementation Person
-(void)show{
    NSLog(@"造的人名字是:%@,年龄是:%d,性别是:%u,还能生存%d年",_name,_age,_gender,_leftLife);
}
@end

main方法调用:

ini 复制代码
int main(int argc, const char * argv[]){
    Person *p2 = [god makePerson];
    Person *p3 = [god makePersonWithName:@"杏花" andGender:(GenderFeMale) andAge:(24) andleftLife:(70)];
    [p2 show];
    [p3 show];
}
相关推荐
萌萌哒草头将军13 分钟前
🚀🚀🚀尤雨溪:Vite 和 JavaScript 工具的未来
前端·vue.js·vuex
Fly-ping20 分钟前
【前端】cookie和web stroage(localStorage,sessionStorage)的使用方法及区别
前端
我家媳妇儿萌哒哒1 小时前
el-upload 点击上传按钮前先判断条件满足再弹选择文件框
前端·javascript·vue.js
天天向上10241 小时前
el-tree按照用户勾选的顺序记录节点
前端·javascript·vue.js
sha虫剂1 小时前
如何用div手写一个富文本编辑器(contenteditable=“true“)
前端·vue.js·typescript
咔咔库奇1 小时前
深入探索 Vue 3 Fragments:从原理到实战的全方位指南
前端·javascript·vue.js
要加油哦~1 小时前
vue | vue 插件化机制,全局注册 和 局部注册
前端·javascript·vue.js
猫头虎-前端技术2 小时前
HTML 与 CSS 的布局机制(盒模型、盒子定位、浮动、Flexbox、Grid)问题总结大全
前端·javascript·css·vue.js·react.js·前端框架·html
Skrrapper2 小时前
【三大前端语言之一】静态网页语言:HTML详解
前端·html