我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Objective-C 入门篇(推荐)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Objective-C 入门篇(推荐)

前言

Objective-C is the primary programming language you use when writing software for OS X and iOS. It's a superset of the C programming language and provides object-oriented capabilities and a dynamic runtime. Objective-C inherits the syntax, primitive types, and flow control statements of C and adds syntax for defining classes and methods. It also adds language-level support for object graph management and object literals while providing dynamic typing and binding, deferring many responsibilities until runtime.

Objective-C(下面简称OC)是由C语言和Smalltalk扩展出来的,是C语言的超集,最大的区别是OC是面向对象的,其火星文写法对于之前从事Java开发的同学颇感蛋疼,OC最大特点之一是使用“消息结构”而不是“函数调用”,所以在运行时执行的代码由运行环境决定,而Java是由编译器决定。个人感觉有关于IOS学习的文章相较于Android质量较低,有可能是苹果系统封闭的原因,本文侧重介绍常用的语法,通过对比Java并结合本人入门的过程和经验,帮助有需求的同学快速掌握OC基本编程,为IOS的入门奠定语言基础。下面首先是写出第一行代码,恭喜正式进入OC学习阶段。


int main(int argc, char *argv[])
{
    @autoreleasepool //创建自动内存释放池
    {
    	//打印输出
        NSLog(@"hello world ios!");
        return 0;
    }
}

下面介绍OC代码的文件扩展名:

文件扩展名 类型
.h 头文件,作用是对类、属性、变量、函数等的声明
.m 实现文件,对头文件的生命实现或者扩展
.mm 实现文件,一般是C++代码

如果实现文件需要引入头文件时,推荐使用#import,跟#include作用相同,优化了确保相同文件只会被引入一次,所以倾向用#import。

基本数据类型

包括:int float double char

类型 字节数 格式化输出
char 1 %c
int 4 %i,%x,%o
unsigned int 4 %i,%x,%o
short int 2 %hi,%hx,%ho
unsigned short int 2 %hi,%hx,%ho
long int 8 %li,%lx,%lo
unsigned long int 8 %lu,%lx,%lo
long long int 8 %lli,%llx,%llo
unsigned long long int 8 %llu,%llx,%llo
float 4 %f
double 8 %f
long double 16 %Lf

其他数据类型

id类型

可以存放任何数据类型的对象,类似Java中的Object类,其被定义为指向对象的指针(本身就是指针了),故定义比如id instance = nil;id类型是多态和动态绑定的基础。

BOOL类型

布尔值为YES/NO或1/0。Java对应是true/false

nil和Nil

nil相当于Java中的null,表示一个对象,这个对象的指针指向空。Nil是定义一个指向空的类而不是对象。

NSString(不可变字符串)

字符串是非常重要常用的,务必要掌握常用的基础用法,包括创建、截取、遍历、比较、大小写转换、搜索等,语义跟基本类似Java。


//字符串
NSString *str1 = @"ABC3456789";
//拼接成新的字符串
 NSString *str2 = [str1 stringByAppendingString:@"wwww"];
NSLog(@"str = %@", str2);
//遍历
for (int i = 0; i < [str2 length]; i++) {
    char temp = [str2 characterAtIndex:i];
    NSLog(@"字符串第 %d 位输出 %c", i, temp);
}
//比较
// sEqualToString方法 :比较字符串是否完全相等,大小写不一样也无法完全匹配。
//hasPrefixe方法:逐一匹配字符串头部。haSuffix方法:匹配字符串的尾部
if ([str2 isEqualToString:str1]) {
    NSLog(@"相等");
}
if ([str2 hasPrefix:@"www"]) {
    NSLog(@"有该头部");
}
if ([str2 hasSuffix:@"www"]) {
    NSLog(@"有该尾部");
}
if ([str2 compare:str options:NSCaseInsensitiveSearch | NSNumericSearch] == NSOrderedSame) {
}
NSLog(@"比较结果:%d", [str2 caseInsensitiveCompare:str1]);
//大小写转换
NSLog(@"str3转大写:%@",[str2 uppercaseString]);
NSLog(@"str3转小写:%@",[str2 lowercaseString]);
NSLog(@"str3首字母转大写:%@",[str2 capitalizedString]);
//字符串截取
NSRange rang = NSMakeRange(2, 2);
NSLog(@"str3截取:%@",[str2 substringWithRange:rang]);
//搜索
NSRange rang1 = [str2 rangeOfString:@"www"];
NSLog(@"location: %d,length: %d",rang1.location,rang1.length);
//替换
//全部替换
NSString *str3 = [str2 stringByReplacingOccurrencesOfString:@" " withString:@"@"];
NSLog(@"替换后字符串为%@", str3);
//局部替换
NSString *str4 = [str2 stringByReplacingCharactersInRange:rang withString:@"met"];
NSLog(@"替换后字符串为%@", str4);

NSMutableString(可变字符串)

创建对象的基本写法是[[NSMutableString alloc]init],*号代表对象,[]代表方法调用,只能通过类或者对象才能调用。[NSMutableString alloc]类似Java中new得到一个对象,然后再调用init初始化方法。


		//创建对象并初始化
		NSMutableString *mStr = [[NSMutableString alloc]init];
        //appendstring:向字符串尾部添加一个字符串。
        //appendFormat:向字符串尾部添加多个类型的字符串,可以添加任意数量与类型的字符串。
        [mStr appendString:@"hello world!"];
        NSLog(@"字符串创建%@", mStr);
        [mStr deleteCharactersInRange:[mStr rangeOfString:@"hello"]];
        //删除
        NSLog(@"字符串删除%@", mStr);
        //插入
        [mStr insertString:@"love you" atIndex: mStr.length];
        NSLog(@"字符串插入%@", mStr);

NSInteger、NSUInteger和NSNumber

NSInteger不是一个对象,而是基本数据类型中的typedef,NSUInteger是无符号的。 当需要使用int类型的变量时,推荐使用NSInteger,这样不需要考虑设备是32位或者64位。NSNumber是一个类,用于包装基本数据类型成为对象,可以理解为Java中的装箱,为一些集合只能存放对象使用,通过字面量方式非常方便将基本数据类型转成对应的对象。例如:


//包装
NSNumber *intNumber = [[NSNumber alloc]initWithInt:43];
//或者字面量方式
NSNumber *intNumber1 = @43;
//还原基本数据类型,解包
NSLog(@"%d",[intNumber intValue]);

集合

集合不能接受nil,nil是作为集合结束标识符。

1. NSArray(不可变)

类似Java中的ArrayList,可以存储不同类型的对象,一般情况下数组元素的类型是相同的,特点是有序、可重复。下面展示一位数组的基本操作: 


//字面量创建方式
    NSArray *arr2 = @[@"aaa",@"bbbbb"];
//工厂方法创建
    NSArray *array = [[NSArray alloc] initWithObjects:@"1", @"2", nil];
    //取最后一个元素
    [array lastObject];
//    取第一个元素
    [array firstObject];
//    数组是否包含某个元素
    [array containsObject:@"1"];
//    数组的大小
    int count = (int) array.count;
//    第一种方式遍历
    for (int i = 0; i < count; i++) {
        NSString *_str = [array objectAtIndex:i];
    }

那么数据要求是多维的呢?多维数组可以理解为数组的数组,通过嵌套的方式,创建如下:


// 字面量创建二维数组并访问
NSArray *arr2 = @[@[@11, @12, @13], @[@21, @22, @23], @[@31, @32, @33]];
// 字面量访问方式(推荐)
NSLog(@"arr2[2][2]:%@", arr2[2][2]);
// 数组对象函数访问
NSLog(@"arr2[2][2]:%@", [[arr2 objectAtIndex:2] objectAtIndex:2]);

2. NSMutableArray(可变的)

派生于NSArray,理解为动态数组,提供增加、删除、插入、替换等语法糖。


		//创建,当然还有其他方式
        NSMutableArray *mutableArr = [NSMutableArray arrayWithObjects:@"one",@"two",@"three", nil];
        //添加
        [mutableArr addObject:@"hello"];
        //替换
        [mutableArr replaceObjectAtIndex:2 withObject:@"tihuan"];
        //删除
        [mutableArr removeObjectAtIndex:1];
        //插入
        [mutableArr insertObject:@"ios" atIndex:1];

多维数组创建方式如下:


   		// 初始化作为列的数组,看做4列
NSMutableArray *columnArray = [[NSMutableArray alloc]initWithCapacity:4];

// 初始化2个一维数组,每个一维数组有4个元素,看做1行4列,2行加起来就是2行4列
NSMutableArray *rowArray1 = [[NSMutableArray alloc]initWithCapacity:4];
NSMutableArray *rowArray2 = [[NSMutableArray alloc]initWithCapacity:4];

// 每个行依次增加数组元素
// 第一行
[rowArray1 addObject:@"11"];
[rowArray1 addObject:@"12"];
[rowArray1 addObject:@"13"];
[rowArray1 addObject:@"14"];

// 第二行
[rowArray2 addObject:@"21"];
[rowArray2 addObject:@"22"];
[rowArray2 addObject:@"23"];
[rowArray2 addObject:@"24"];

// 分别打印数组
NSLog(@"myRowArray1: %@", rowArray1);
NSLog(@"myRowArray2: %@", rowArray2);
NSLog(@"myColumnArray: %@", columnArray);

字典

类似于Java中的HashMap,是一种映射型数据结果,存储键值对,有可变和不可变两种类型。

NSDictionary

主要特点是不可变,如果集合初始化完成,将内容无法修改,无序。


	//标准创建
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"cat",@"name1",@"dog",@"name2", nil];
    //字面量创建
    NSDictionary *dict1 = @{@"name1":@"cat",@"name2":@"dog"};
	//第一种遍历
    for (NSString *key in [dict1 allKeys]) {
        NSLog(@"key: %@,value: %@", key, dict1[key]);
    }
    //第二种遍历方式,通过遍历器
    NSEnumerator *rator = [dict keyEnumerator];
    NSString *temp;
    while (temp = [rator nextObject]) {
        NSLog(@"%@", temp);
    }
    //获取元素
	dict1[@"name"];
	[dict1 objectForKey:@"name"];
	//集合元素的个数
	NSInteger count = dict1.count;
	//沙盒文件存储和读取Plist
	[dict5 writeToFile:@"路径" atomically:YES];
	NSDictionary *dict7 = [NSDictionary dictionaryWithContentsOfFile:@"路径"];

NSMutableDictionary

NSMutableDictionary是NSDictionary的子类。NSMutableDictionary是可变的,动态添加、更改、删除元素,因此不能使用字面量方式(@{})来创建一个可变字典。如果是不可变字典,出现了同名的key,那么后面的key对应的值不会被保存,反之是可变字典,出现了同名的key,那么后面的值会覆盖前面的值。


//创建
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//添加
[dict setObject:@"dog" forKey:@"name"];
[dict setValue:@"18" forKey:@"age"];
//会将传入字典中所有的键值对取出来添加到dict中
[dict setValuesForKeysWithDictionary:@{@"name1":@"dog"}];
//取元素
[dict objectForKey:@"name"];
dict[@"name"];
//删除
[dict removeAllObjects];
[dict removeObjectForKey:@"name"];
[dict removeObjectsForKeys:@[@"name", @"age"]];
//更新,如果利用setObject方法给已经存在的key赋值,新值会覆盖旧值
[dict setObject:@"20" forKey:@"age"];
dict[@"age"] = @"30";

NSSet && NSMutableSet

具有很好的存取和查找功能,与NSArray相比NSSet的元素没有索引,特点是无序,不可重复,类似Java中的HashSet,其中NSMutableSet提供计算交并集的方法。

NSSet存储元素的过程:

注意:推荐使用字面量方式创建对象,可以缩短代码长度,增加可读性。但是在创建数组的时候要注意,如果含有nil就会抛异常,因为字面量实际上”语法糖“,效果等同于先创建一个数组,然后再把所有的对象添加进来,保证数组不添加nil。

消息传递

前言提到Objective-C最大特点之一是继承了Smalltalk消息传递模型,因此在OC中的方法调用准备的说法是消息传递,类别与消息关系松散,调用方法是给对象发送消息,而方法是对消息的回应,所有消息的处理直到运行时(即runtime)才会动态确定,并交由类自行决定如何处理收到的消息。总结是一个类不保证一定会回应收到的消息,当收到的一个无法处理的消息,会抛出异常。

Java或者C++方法调用:

obj.method(argument);

OC方法调用:

[obj method: argument];

我们都知道在Java或者C++中,如果类没有定义method方法,那么编译肯定不会通过,但是在OC中,理解是发送method的消息给obj,obj收到消息后再决定如何回应消息,如果类内定义了method方法则运行,反之不存在运行期抛出异常。

所有面向对象的编程都有类的概念,用于封装数据,这样的语言特性都有封装、继承和多态。OC对象是类在运行期的实例,包含了类声明的实例变量、内存拷贝、类成员的指针等。由于OC是C语言的超集,类由两个部分组成,分别是定义(interface)和实现(implementation),下面举个?。新建一个People类,@interface是接口声明的开始,@end终止结束,所有的OC编译指令都是以”@“开始的。类的实现是通过@implementation指令开头以@end结束。对应People.h和People.m两份文件,下图是类声明(People.h)的展示,主要包括继承关系、成员变量、属性、方法声明等,方法的具体实现是在People.m。

下图是方法声明的展示:

当然不止Interface区块可以定义变量,Implementation区块也可以定义,两者区别是访问权限不一。

前者默认权限为protected,而implementation区块的实体变量则默认为private,所以类别私有可以放在implementation区块。

访问修饰符

  • @public:任何位置可以访问。
  • @protected:默认情况下成员变量的修饰符。
  • @private:变量只限于声明它的类访问,不允许被继承。
  • @package:限定在当前包内,类似于Java包的概念。

属性

成员变量是给类内使用的,属性是作为类外访问成员变量的接口,用于封装对象的数据,通过@property声明,编译器自动生成setter和getter方法,此过程称为”自动合成“。类实现文件中@synthesize语法可以指定实例变量的名字,一般不推荐这样做。@dynamic语法是告诉编译器不要自动合成,在OC中访问修饰符很少用到,主要是靠声明属性取值。

属性有五个常用的特质修饰:

assign:针对基本数据类型赋值操作。 strong:定义一种”拥有关系“,属性设置新值时,先保留新值,并释放旧值,然后再将新值设置。 weak:跟strong相反,属性所指的对象销毁时,属性值也会清空。 copy:设置方法不保留新值,而是拷贝一份。 nonatomic:非原子,非线程安全类型。

Q&A:为什么NSString 、 NSArray、 NSDictionary的属性要用copy,集合的深浅拷贝是怎样的?

copy属性作用是为变量赋值的时候系统自动copy一份内存出来,修改新变量不会影响旧变量。在Apple规范中,NSString,NSArray,NSDictonary,推荐使用copy属性,而其NSMubtableString,NSMutableArray, NSMutableDictonary属性则使用strong属性。


NSString *sourceString = [NSString stringWithFormat:@"hello ios"];
//不产生新的内存空间
NSString *copyStr = [sourceString copy];
//产生新的内存空间
NSMutableString *mutableStr = [sourceString mutableCopy];
NSLog(@"sourceString : %@   %p",sourceString,sourceString);
NSLog(@"copyStr : %@    %p",copyStr,copyStr);
NSLog(@"mutableStr : %@     %p",mutableStr,mutableStr);

使用strong这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。例如:


//代码块   
NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
NSString *stringCopy = [string copy];
NSLog(@"string address is: %p",string);
NSLog(@"stringCopy address is: %p",stringCopy);

结果:内存地址不同


NSMutableString *string = [NSMutableString stringWithString:@"origin"];
//NSString *stringCopy = [string copy];
NSString *stringCopy = string;
[string appendString:@"change"];
NSLog(@"string address is: %p",string);
NSLog(@"stringCopy address is: %p",stringCopy);

结果:内存地址相同

结论:

可变对象指向不可变对象会导致不可变对象的值被篡改,所以需要copy属性。用@property声明NSString、NSArray、NSDictionary 经常使用copy关键字,是因为他们有对应的可变类型NSMutableString、NSMutableArray、NSMutableDictionary,彼此之间可能进行赋值操作,为了不可变对象中的内容不会被无意间变动,应该在设置新属性值时拷贝一份。

浅拷贝:

在Java中浅拷贝如果是基本数据,则拷贝的是基本数据的值;如果是对象,则拷贝的是内存地址,修改该对象会影响另外一个对象。在OC中是对指针的拷贝,拷贝后的指针和原本对象的指针指向同一块内存地址,故同样会相互影响。

深拷贝:

OC中不仅拷贝指针,而且拷贝指针指向的内容,指针指向不同的内存地址,故修改不会相互影响原本对象。

非集合类对象中:对immutable对象进行copy操作,是指针复制(浅拷贝),mutableCopy操作时内容复制;对mutable对象进行copy和mutableCopy都是内容复制(深拷贝)。

方法

通过”+“、”-“分别声明类方法和实例方法,方法如果带有多个参数,参数在方法名之后接冒号定义,多个参数由空格隔开,如果参数个数可变,使用逗号接省略号。例如:


//无参数
- (void)print;
//有参数
- (void)print:(int)a andB:(int)b;

构造方法

第一种是重写init方法,第二种是自定义。



- (instancetype)init
{
    self = [super init];
    if (self) {
        _peopleName = @"hello ios";
    }
    return self;
}


- (instancetype)initWithNameAndAge:(NSString *)name andAge:(int)age
{
    self = [super init];
    if (self) {
        _peopleName = name;
        _peopleAge = age;
    }
    return self;
}

创建类对象

所有对象和类的引用都是通过指针实现,严格地说指针就是一个地址,是一个常量,而指针变量可以被赋值不同的指针值,创建的对象就是一个指针变量,通过[People alloc]创建一个People对象,分配了内存,init是初始化对象。构造方法有两种方式,第一种是重写init方法,第二种是自定义。


People *p1 = [[People alloc] init];
//调用自定义的构造方法
People *p3 = [[People alloc] initWithNameAndAge:@"mingzi" andAge:12];
//调用方法
[p3 print];

在OC 2.0中,如果创建的对象不需要参数,可以直接使用new:

People *p1 = [People new];

self

作为OC的一个关键字,代表当前类的对象,类似Java中的this,最大的作用是让类中的一个方法调用该类另外一个方法或者成员变量,可以理解”当前类谁调用了这个方法,self就代表谁“。

继承

同Java一样只能单继承,只允许最多有一个直接父类。例如:定义一个父类Computer和子类MacBook。注意方法重写类似Java,子类要重写父类方法不需要重新声明重写方法,在实现部分直接重写目标方法即可。如果需要子类调用父类的方法,可以通过super关键字调用。


//Computer.h文件
#import <Foundation/Foundation.h>
@interface Computer : NSObject
@property(nonatomic,strong)NSString *name;
-(void)calculate;
@end

//  Computer.m
#import "Computer.h"
@implementation Computer
@synthesize name;
-(void) calculate{
    NSLog(@"i can calculate");
}
@end

//  MacBook.h
#import "Computer.h"
@interface MacBook : Computer
@end

//  MacBook.m
#import "MacBook.h"
@implementation MacBook
@end

//main.m
int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        MacBook *macBook = [[MacBook alloc] init];
        macBook.name = @"mac";
        [macBook calculate];
    }
}

多态

封装、继承和多态是面向对象编程语言的三大特性,OC的多态是不同对象对同一消息的不同响应方式,实际过程主要分为三种:

  • 继承
  • 重写
  • 指向子类的指针指向父类

可以看出跟Java的多态类似,理解起来应该比较容易,注意是没有方法重载的,在OC中不允许。

Runtime

实例:用Runtime新增一个类Person, person有name属性,有sayHi方法


#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import <objc/runtime.h>
#import <objc/message.h>
void sayHi(id self, IMP _cmd, id some)
{
    //self指的是调用该方法传过来的类
    NSLog(@"%@说:%@,我%@岁", [self valueForKey:@"name"], some, object_getIvar(self, class_getInstanceVariable([self class], "_age")));
}

int main(int argc, char *argv[])
{
    @autoreleasepool
    {
        //该方法动态创建一个类,arg1:继承自哪个类 arg2:新建类的名称 arg3:extraBytes
        Class Person = objc_allocateClassPair([NSObject class], "Person", 0);
        //添加两个实例变量name和age,arg2:变量名称,arg3:内存地址大小,arg5:变量类型
        class_addIvar(Person, "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
        class_addIvar(Person, "_age", sizeof(int), sizeof(int), @encode(int));
        //注册方法名
        SEL s = sel_registerName("say:");
        //arg3:IMP是“implementation”的缩写,这个函数指针决定了最终执行哪段代码
        //arg4:方法的参数及返回值
        class_addMethod(Person, s, (IMP)sayHi, "v@:@");
        //通过该类创建一个实体的对象
        id peopleInstance = [[Person alloc]init];
        //给对象的 name 实例变量赋值,下面是第二种赋值方式
        [peopleInstance setValue:@"XQM" forKey:@"name"];
        //Ivar nameIvar = class_getInstanceVariable(Person, "_name");
        //object_setIvar(peopleInstance, nameIvar, @"XQM");
        //获取实例变量
        Ivar ageIvar = class_getInstanceVariable(Person, "_age");
        //为变量赋值
        object_setIvar(peopleInstance, ageIvar, @21);
        //调用sayHi方法,arg2:注册指定的方法;arg3:带上有一个字符串的参数
        ((void(*)(id, SEL, id))objc_msgSend)(peopleInstance, s, @"大家好");
        //调用完成,将对象置为空
        peopleInstance = nil;
        //通过 objc 销毁类,销毁的是一个类不是对象
        objc_disposeClassPair(Person);
    }
}

主要流程是:

定义类的方法->objc_allocateClassPair创建类->class_addIvar给类添加成员变量->sel_registerName注册方法名->class_addMethod给类添加定义的方法->注册该类->创建类对象->class_getInstanceVariable获取成员变量,并通过object_setIvar赋值->objc_msgSend调用方法->释放对象,销毁类

Category(类别)

Objective-C借用并扩展了Smalltalk实现中的"分类"概念,用以帮助达到分解代码的目的。类别主要特点是不能增加属性或者成员变量、增加类功能和分离类实现,举个例子: 在UIImageView增加了图片异步加载的功能


@interface UIImageView (ImageViewLoader) <AysncImageDownloaderDelegate>
- (void)setOnlineImage:(NSString *)url placeholderImage:(UIImage *)image withRow:(NSNumber *)row;
@end

@implementation UIImageView (ImageViewLoader)

- (void)setOnlineImage:(NSString *)url placeholderImage:(UIImage *)image withRow:(NSNumber *)row;
{
    self.image = image;
    AsyncImageDownLoader *downloader = [AsyncImageDownLoader sharedImageDownloader];
    [downloader startWithUrl:url delegate:self withRow:row];
}
@end

Extension(拓展)

拓展也经常用到,主要特点是增加ivar、用于接口分离等。例如:ViewController的实现文件增加@interface ViewController (),支持定义属性等。


@interface ViewController ()
@property (nonatomic, copy) block b;
@end

@implementation ViewController
@end

异常处理

OC的异常处理极其类似Java中的,包括4个指示符,分别是@try、@catch、@throw、@finally。可能存在异常的代码写在@try块,异常处理逻辑写在@catch,@finally块的代码总是要执行的,@throw作用是抛出异常。

协议

类似Java中的接口(interface),类似多重继承功能,支持协议继承协议,通过定义一系列方法,然后由遵从协议的类实现这些方法,协议方法可以用@optional关键字标记为可选,@required关键字标记为必选,编译器会出现检查警告,一般来说还是可以编译通过。下面看下语法:


@protocol ClickDelegate
- (void)click;
- (void)unclick;
@end

协议最常应用在委托,分为委托方和代理方,委托方负责定义协议、通过id类型持有协议和调用协议的方法,而代理方则遵从协议、设置协议代理对象以及实现协议方法即可。

block

类似Java中的Lambda表达式,比较复杂,笔者的理解还未达到一定解说程度,所以这里先不做解释,放到后续的文章中介绍。

内存管理

Java的内存管理是由垃圾回收器负责,OC中引入自动引用计数(ARC),内存管理交由编译器决定。引用计数是每个对象都有一个计数器,如果对象继续存活,计数器递增其引用计数,用完之后递减引用计数,如果计数变为0,表示对象可以被释放了。NSObject协议声明了Retain、release和autorelease方法用于操作计数器,分别是递增、递减、自动释放操作,所有的对象都是收集器的工作对象。

ARC:自动引用计数,编译器自动生成retain/release MRC:手动管理引用计数,旧版本使用 autoreleasepool:延迟自动释放

strong/weak/assgin最佳实践

基本类型:assgin; delegate->week; 集合和block用copy; 其他用strong; block中的self用weak打破循环引用。

参考资料

https://www.jianshu.com/p/eb713b1f22dc https://www.jianshu.com/p/6ebda3cd8052 https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Objective-C 入门篇(推荐)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Objective-C 入门篇(推荐)

目录前言基本数据类型其他数据类型id类型BOOL类型nil和NilNSString(不可变字符串)NSMutableString(可变字符串)NSInteger、NSUInteger和NSNumber集合1. NSArray(不可变)2.
2022-05-20

怎么进行Objective-C的入门

怎么进行Objective-C的入门,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前言Objective-C(下面简称OC)是由C语言和Smalltalk扩展出
2023-06-21

2019年Python入门书籍推荐

大概是一时改变不了之前的学习习惯,所以很多Python小白都来问我有什么适合的Python入门书籍推荐。接下来我就为大家推荐几本经典的:(请大家根据自己以下六种情况对号入座,挑选适合自己的 Python 入门书籍)一.如果你一点Python
2023-01-31

入门级云服务器推荐

如果您正在寻找一个低成本、易于使用的云服务器,那么以下是一些可能适合您的入门级云服务器建议:IaaS服务:使用公有云提供商的基础设施,如GoogleCloudPlatform或Salesforce.com等,您可以按需付费或根据您的需求来购买和配置所需的基础设施。您可以选择租用和托管云资源,但最重要的是确保您的云服务器是高可用性、高性能和高可靠性的。PaaS服务:使用PaaS服务的入门级云
2023-10-26

android okhttp的基础使用【入门推荐】

这篇文章主要总结Android著名网络框架-okhttp的基础使用,后续可能会有关于他的高级使用。 okhttp是什么 okhttp是Android端的一个Http客户端,其基础功能相当于Android自带的HttpURLConnectio
2022-06-06

入门级云服务器推荐哪个

如果您只需要一个基础的云计算服务器平台,您可以考虑以下几个品牌的云服务器产品:AmazonEC2:这是亚马逊云计算服务(AWS)的核心产品之一,提供高性能、低延迟的IaaS云服务。AmazonVPC:这是亚马逊云计算服务AmazonAWS的一部分,提供高容错性的虚拟机存储服务。AmazonDynamoDB:这是亚马逊云计算服务AmazonAWS旗下的开源产品,提供大数据存储和分析能力。
2023-10-26

入门级云服务器推荐哪款

如果您只需要基本的计算、存储和网络资源,那么可以考虑购买一台入门级的云服务器——价格较为实惠的服务器品牌。这些服务器品牌包括亚马逊AWS、阿里云、腾讯云、华为云等,它们都提供了各种型号的服务器产品,其中最受欢迎的是亚马逊AWSEC2(ElasticLoadCenter),适合企业用户和小型团队使用。除了价格外,这些云服务器还提供了各种功能,如可扩展性、负载均衡、多用户支持、弹性计算、容错等。
2023-10-26

云服务器入门级品牌推荐

1.AWS(亚马逊云服务)AWS是全球领先的云计算服务提供商之一,其云服务器产品EC2(ElasticComputeCloud)提供了丰富的功能和灵活的配置选项。AWS的EC2实例性能稳定可靠,具有高可用性和可扩展性,适用于各种规模的应用和工作负载。2.Azure(微软云服务)Azure是微软提供的云计算平台,其云服务
2023-10-27

WordPress初学者必读:入门指南推荐

WordPress是一个广泛应用于网站建设的开源内容管理系统,它简单易用且功能强大,适合初学者快速入门并打造专业网站。本文将为WordPress初学者提供入门指南,包括安装、主题、插件等基础知识,并附带具体的代码示例。第一部分:安装Wor
WordPress初学者必读:入门指南推荐
2024-02-29

入门级云服务器推荐哪款好

如果您正在寻找一个适合在互联网上托管大量数据的云服务器,我推荐您选择OpenStack公共云。它是一个广受欢迎的云计算基础架构,为客户提供高可用性、可扩展性和灵活性。以下是一些OpenStack的入门级云服务器推荐:MongoDB:MongoDB是一个免费开源的Linux版本的数据库系统,它可以轻松地存储和访问大量数据,并提供强大的查询和报告功能。Cloudstack:Cloudstac
2023-10-26

入门级云服务器推荐哪个品牌

如果您正在寻找入门级云服务器,我会推荐您选择AWS的AmazonWebServices(AWSAzure)。它是亚马逊(Amazon.com)的云计算服务,可以帮助您节省成本并提高云计算服务的效率和灵活性。AWSAzure提供了很多有用的功能和服务,例如实时迁移数据、多云备份、安全性、可扩展性和可靠性等等。此外,AWSAzure还提供了许多云计算选项,例如弹性基础设施(ElasticFabri
2023-10-26

入门级云服务器推荐哪个型号

如果您正在寻找一个云服务器入门级别的选择,我可以为您提供一些建议:阿里云:阿里云的云服务器提供了多个选择,包括入门级的ApsaraCloudDocker和AmazonCloudAlienware,它们的价格相对较低,而且具有高可靠性和安全性。Dropbox:Dropbox也是一个非常受欢迎的云服务器选择,它提供了很多选择,例如AmazonCloudCluster和AmazonKavinVa
2023-10-26

入门级云服务器推荐哪款手机

如果您是初学者,推荐以下几款适合您的入门级云服务器:AWSAzureHosting(阿里云)这款云服务器可以在阿里云上轻松部署和管理您的网站。阿里云提供了多种配置选项和支持,让您可以自定义您的网站架构和配置。无论您是新手还是有经验的企业用户,AWS都将帮助您更快地创建和维护您的网站。此外,阿里云还提供了高可用性,使您的网站更容易地从故障切换到阿里云。AmazonKylin(亚马逊AWS)
2023-10-26

入门级云服务器推荐哪款好用

如果您正在寻找一个云计算服务器的入门级产品,我可以向您推荐以下几款产品:阿里云CloudPlatform:该产品是一个集成的云计算解决方案,提供了高性能、安全、可扩展性等方面的优势。价格相对合理,适合中小企业。亚马逊AWS:AWS是全球最受欢迎的云计算服务提供商之一,提供了高质量的云计算服务和基础设施,以及灵活的价格。此外,AWS还有一些针对企业和机构的优惠和礼品。UCloudCloudWest:该产品提供了高效、稳定的数据中心...
2023-10-27

入门级云服务器推荐哪个型号好

云服务器的基本配置在选择云服务器时,基本配置是非常重要的。基本配置包括服务器的硬件配置,如CPU、内存、存储等。云服务器通常支持多种硬件配置,如IntelXeon、AMDFX等。因此,如果您需要访问大量数据和存储资源,那么您需要选择高端的硬件配置。如果您需要更多的计算资源,您可以选择低端配置的云服务器。云服务器的可扩展
入门级云服务器推荐哪个型号好
2023-10-28

入门级云服务器推荐哪款好一点

AWS:AWS在全球范围内都有很高的知名度,它的产品线较为全面,包括云计算、数据中心、云存储、基础软件等。AmazonRedHat:AmazonRedHat是AmazonWebServices的子公司,主要提供云服务器、云存储服务和云安全产品。AmazonGo:AmazonGo是AmazonAWS推出的一款智能购物中心,通过自动化技术为用户提供快速购物体验。DynamicCloudAppliance:DynamicCloudAppliance提供高性能计算、高可靠性和大量的云存储空间,以满...
2023-10-27

基于Spring MVC 简介及入门小例子(推荐)

一、什么是 Spring MVCSpring MVC 属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 里面,是一个强大灵活的 Web 框架。Spring MVC 提供了一个 Dispatcher
2023-05-31

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录