OC--初识


前言

1.类与对象
2.方法
3.成员变量
4.隐藏和封装


一、类与对象

首先,类是什么?

类是面向对象的重要内容,可以把类当作一种自定义的数据类型,用类来定义的变量相当于指针类型的变量。

1.面向对象和面向过程

在这里插入图片描述

2.类和对象

类是某一批对象的抽象概念。对象是一个个实体。(对象类似于C中的结构体)

在这里插入图片描述
接口部分:
@interface用与于声明定义类的接口部分,@end表示结束。
成员变量,用于描述该类的对象的数据状态,方法用来描述类的行为。
我们一般将类的定义的接口声明放在头文件
实现部分:
1.类名与接口部分的类名相同(函数的定义于函数的使用的函数名相同)
2.可以在类名后使用:父亲表示继承了某个父类
3.必须为类的声明部分的每个方法提供定义(函数声明后需要定义)
C中的类似定义

类似于C中我们将部分函数及结构体放在一个.h文件中。然后在main函数所在的文件中包含这个.h文件。

在这里插入图片描述
在这里插入图片描述
这里我们需要注意

OC中建议成员变量名以下划线_开始。并且第一个单词的首字母小写,其余单词的首字母大写,剩余字母小写,单词与单词之间不需要任何分割符。以这样的方式来定义成员变量名。

3.对象的产生和使用

1.对象的定义:

类型 *变量名

2.对象的创建:

[ [ 类名 alloc ] 初始化方法 ]

alloc 为关键字,作用相当于C中的malloc,负责为对象开辟空间。
所有的类都有一个默认的初始化方法init,因此上面的写法等同于[ [类名 alloc ]init ]

4.对象和指针

本质来说,类是一种指针类型的变量。因此,程序中定义的类型只是存放一个地址,它被保存在main()函数的动态存储区,指向实际的对象,而真正的对象存放在堆内。

在这里插入图片描述
如果堆内存中的对象没有任何变量指向该对象,那么程序将无法访问该对象。
在这里插入图片描述

5.id类型

OC提供了一个id类型,可以代表所有对象的类型。也就是说,任意类型的对象都可以赋值给id类型。
当使用id类型时,OC会在运行时判断该对象的类,并在运行时确定需要动态调用的方法
程序将会在运行时自动检测变量所指的实际的类型。

二、方法(类似C中的函数)

1.定义

方法是类或对象的额行为特征的抽象,也是类或对象最重要的组成部分。

方法在逻辑上要么属于类,要么属于对象。

方法不能独立存在,必须属于类或对象,方法要么属于这个类,要么属于该类的一个对象
方法使用+标识符,这个方法就属于这个类,使用-标识符,就属于这个类的实例。
注意虽然传参传的是副本,但也是地址传递

2.形参个数可变的方法(NSLog()函数)

本质上,可变参数也是一个类似于数组的结构

如果在定义方法时,在最后一个形参名后增加逗号和三点(,…)就表明该形参可以接受多个参数值。
例如:

在这里插入图片描述
个数可变的形参只能处于形参列表的最后,一个方法中最多只能有一个个数可变的形参
🌰
类的接口

#import<Foundation/Foundation.h>
@interface VarArgs:NSObject
-(void)test:(NSString*)name,...;

@end;

类的实现:

#import "0605.h"

@implementation VarArgs
-(void)test:(NSString *)name, ...{
    
    va_list argList;
    if(name){
        NSLog(@"%@",name);
        va_start(argList,name);
        NSString* arg=va_arg(argList,id);
        while(arg){
            NSLog(@"%@",arg);
            arg=va_arg(argList,id);
            
            
        }
        va_end(argList);
        
    }
}
@end

测试:

#import"0605.h"
#import<Foundation/Foundation.h>
int main(){
    @autoreleasepool {
        VarArgs* va = [[VarArgs alloc]init];
        [va test:@"heihei",@"nuonuo",@"nana",nil];
        
    }
    
}

运行结果如下:
在这里插入图片描述

3.方法的声明

在这里插入图片描述

返回值类型:可以是oc允许的任何类型。如果声明了返回值类型,则该函数内必须有一个有效的return语句,来返回和声明的返回类型一致的数据。
类似于C中的函数,必须返回和函数类型相同的值。(此处函数类型为结构体,返回值类型也应该为结构体)

struct Node* CreatNode(int data) {
	struct Node* NewNode = (struct Node*)malloc(sizeof(struct Node));
	NewNode->data = data;
	NewNode->next = NULL;
	return NewNode;
}

在oc的方法声明中,所有的类型(包括void)都应该用圆括号括起来。

4.方法签名

oc中方法签名后边带冒号和不带冒号是完全不同的意思
不带冒号表示他是一个不带形参声明的方法,而带一个冒号表示它是带一个形参声明的方法。

5.方法与函数的不同

1.函数可以传值也可以传址,但方法都是传址
2.函数可以在任意位置定义,方法只能在类中定义
3.方法有(+)(-)标识符的区分,函数没有
4.函数可以独立执行,但方法执行时必须使用类或对象作为调用者

6.🌰

#import<Foundation/Foundation.h>
@interface Person:NSObject{
    NSString* _name;
    int _age;
}
-(void) steName:(NSString*)name andAge: (int)age;
-(void)say:(NSString*)content;
-(NSString*)info;
+(void)foo;
@end;

#import "0605.h"

@implementation Person{
    int _testAttr;
    
}
-(void)setName:(NSString*)n andAge:(int) a{
    _name = n;
    _age = a;
}
-(void)say:(NSString*)content{
    NSLog(@"%@",content);
    
}
-(NSString*)info{
    [self test];
    return [NSString stringWithFormat:@"我是一个人,我叫%@,年龄是%d",_name,_age];
}
-(void)test{
    NSLog(@"heihei");
}
+(void)foo{
    NSLog(@"person");
}
@end

类的接口:

#import<Foundation/Foundation.h>
@interface Dog:NSObject
-(void)jump;
-(void)run;
@end;

类的实现:

#import "0605.h"

@implementation Dog
-(void)jump{
    NSLog(@"start jump");
    
}
-(void)run{
    Dog* d=[[Dog alloc]init];
    [d jump];
    //将以上两行代码换位下边一行也可
    //[self jump];
    NSLog(@"start run");
}
@end

测试:

#import"0605.h"
#import<Foundation/Foundation.h>
int main(){
    @autoreleasepool {
        Dog* dog=[[Dog alloc]init];
        [dog run];
    }
}

代码运行结果:
在这里插入图片描述

三.成员变量

1.定义

在这里插入图片描述
只要实例存在,程序就可以访问该实例的变量。方法如下:
OC的成员变量都是实例变量,OC并不支持真正的类变量。
实例—>实例变量

//类的接口
#import<Foundation/Foundation.h>
@interface Person:NSObject{
    @public
    NSString* _name;
    int _age;
    
}
@end;



//类的实现
@implementation Person
@end;


//测试
int main(){
    @autoreleasepool {
        Person* p=[[Person alloc]init];
        NSLog(@"_name=%@,_age=%d",p->_name,p->_age);
        p->_name=@"nuonuo";
        p->_age=29;
        NSLog(@"_name=%@,_age=%d",p->_name,p->_age);
    }
    
}

代码结果如下:
在这里插入图片描述

2.模拟类变量

static不能用于修饰成员变量

3.单例模式

什么是单例类?

如果一个类始终只能创建一个实例,这个类就被称为单例类。 单例类可以通过static全局变量来实现,每次程序需要获取该实例时,先判断该static全局变量是否为nil,如果该全局变量为nil,则初始化一个值并付给该全局变量;如果不为nil,直接返回该全局变量指向的实例即可。

什么时候需要用到单例类?

在某些时候,程序多次创建的某个类的对象没有任何意义,由于不停的创建对象回收对象,还可能造成系统性能下降。此时程序需要保证该类只有一个实例,

类的接口如下:

#import<Foundation/Foundation.h>
@interface Singleton:NSObject
+(id)instance;
@end;

类的实现:

#import "0605.h"
@implementation Singleton
static id instance= nil;
+(id)instance{
    if(!instance){
        instance=[[super alloc]init];
        
    }
    return instance;
}
@end;

测试:

#import"0605.h"
int main(){
    @autoreleasepool {
        NSLog(@"%d",[Singleton instance]==[Singleton instance]);
        
    }
}

代码结果:
在这里插入图片描述

四.隐藏和封装

1.定义和优缺点

封装是指面向对象的三大特征之一,它是指将对象的信息隐藏在对象内部,不允许外部程序直接访问内部信息。而是通过该类所提供的方法来实现对内部信息的访问和操作。
封装的优点:
1.隐藏类的实现细节
2.便于修改,提高代码的可维护性
3.使试用制只能通过事先预定的方法来访问数据
如何实现良好的封装?
1.将对象的成员变量和实现细节隐藏起来
2.把方法暴露出来,

2.使用访问控制符

@private(类似局部变量出作用范围后就不能)
彻底隐藏成员变量,使这个成员变量只能在该类的内部进行访问。
在类的实现部分定义的成员变量相当于默认使用这种访问权限
@package
部分隐藏成员变量,可以在当前类及当前类的同一映像的人易部分进行访问。
@protected
在当前类,当前类的子类任意访问。
在类的接口部分定义的成员变量相当于默认使用这种访问权限。
@public
公共访问权限,可以任意的进行访问。
在这里插入图片描述
类的接口:

#import<Foundation/Foundation.h>
@interface Person :NSObject{
    @private
    NSString* _name;
    int _age;
    
}
-(void)setName:(NSString*)name;
-(NSString*)name;
-(void)setAge:(int)age;
-(int)age;
@end;

类的实现:

#import "0605.h"
@implementation Person
-(void)setName:(NSString*)name{
    if([name length]>6||[name length]<2){
        NSLog(@"error");
        return;
    }else{
        _name=name;
    }
}
-(NSString*)name{
    return _name;
}
-(void)setAge:(int)age{
    if(_age!=age){
        if(age>100||age<0){
            NSLog(@"error");
            return;
        }else{
            _age = age;
        }
    }
}
-(int)age{
    return _age;
}
@end;

测试:

#import"0605.h"
int main(){
    @autoreleasepool {
        Person* p= [[Person alloc]init];
        [p setAge:1000];
        NSLog(@"error:%d",[p age]);
        [p setAge:30];
        [p setName:@"nana"];
        NSLog(@"_name=%@",[p name]);
        
    }
    
}

代码结果 ;
在这里插入图片描述类的接口

#import <Foundation/Foundation.h>

@interface User : NSObject
@property(nonatomic)NSString* name;
@property NSString* pass;
@property NSDate* birth;

@end

类的实现:

#import "0607.h"
@implementation User
@synthesize  name=_name;
@synthesize pass;
@synthesize birth;
-(void)setName:(NSString*)name{
    self->_name=[NSString stringWithFormat:@"+++%@",name];
}
@end

测试:

#import"0607.h"
int main(){
    @autoreleasepool {
        User* user=[[User alloc]init];
        [user setName:@"nuonuo"];
        [user setPass:@"12334"];
        [user setBirth:[NSDate date]];
        NSLog(@"%@,%@,%@",[user name],[user pass],[user birth]);
    }
}

测试结果 :
在这里插入图片描述

五、简单的举例

这里我们通过一个简单的小例子,来认识一下OC和C的相似和不同

1.OC的实现

#import <Foundation/Foundation.h>
//#import就相当于C中的#include
//<Foundation/Foundation.h>也就类似于C中的<stdio.h>
int main(int argc,char* argv[]){
//主函数依旧是main函数
    @autoreleasepool {
        NSLog(@"Hello Object-C");
        //NSLog函数就类似于C中的printf
    }
    return 0;
    //返回方式也相同
}

在这里插入图片描述
第一行的2022-5-22 22:34:35.824506+0800是执行这段代码的时间
第一行的gy-c是 程序的名称
2569是 进程 的编号
91057是 线程 的编号
Hello Object-C 即为输出的内容

2.C的实现

#include <stdio.h>
int main() {
    printf("Hello, Object-C\n");
    return 0;
}

在这里插入图片描述
C这里只输出了需要输出的内容,不像OC输出了许多东西
我们也可以发现一些东西
1.输出的东西不太一样
2.OC会自动换行
3.OC和C的注释方法一样


总结

只是刚刚开始学,以后会继续补充。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山河丘壑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值