OC加强-day03

时间:2024-08-04 20:03:50

#program mark - 0_18 分类的使用注意 [掌握]

1.分类的作用

作用:讲一个类分为多个模块,将相似功能的方法写在同一个模块中,方便我们后面代码的维护

"强调

1.分类中只能写方法的声明和实现,你不要直接去写属性,写了立即报错

2.在分类的.h中用@property声明的属性,不会生成属性,只会在分类的.h里面生成"所谓的"属性的set/get的声明.

3.在分类中到底如何访问本类的属性.

1>分类中是不能直接访问本类中的真私有属性,但是可以通过set/get方法访问

2>分类中可以直接访问本类.h中@interface中直接声明的属性

#program mark - 0_19 非正式协议 [现在先听懂,等学了Foundation框架再回来复习]

为系统自带的类写分类,就叫做非正式协议

#program mark - 02 延展的基本使用 [掌握]

"强调

1.类延展也是类的一种分类,这个分类和本类公用一个.m,所以它是一个只有.h的文件

2.类延展没有没有名字

"练习

给一个类YYNetworkTool,添加一个类延展download

3.和普通分类的区别

1>普通分类直接创建属性,会立即报错,类延展却可以创建属性

2>普通分类用@property生成的属性,不会生成属性,只会在分类的.h里面生成"所谓的"属性的set/get的声明,但是延展,会在主类的.m中生成私有属性和set/get的实现.以及当前类延展的.h中生成属性的set/get方法的声明.

"注意:由于延展和主类公用一个.m,又由于编译只编译.m文件.所以要在主类中导入类延展的.h,否则延展中的代码没有效果

#program mark - 03 延展的使用场景 [掌握]

1.什么叫私有的@property

生成的属性的set/get的声明也在.m里面

2.类延展到底有什么用?

就是用来声明不想在类外部使用的属性和方法.当方法或者属性仅限于当前类内部使用的时候

#program mark - 04 block变量的声明 [掌握]

1.变量是什么?

变量就是内存中若干个字节,用来存储数据.

int 型变量 里面存储 整型数据

"函数的指针"类型 里面存储 一个函数的地址

block类型的变量 里面存储 一段代码

2.变量的声明

1>int

数据类型 变量名;

int    num_int;

2>函数的指针

//函数的指针指向一个返回值为void,参数是两个double型的函数

void (*p)(double num1,double num2);

//函数的指针指向一个返回值为void,没有参数的函数

void (*p1)();

3>block

//定义一个block的变量存储一个返回值为void,参数是两个double型代码块

void (^xiaoyueBlock)(double num1,double num2);

//定义一个block的变量存储一个返回值为void,没有参数的代码块

void (^xiaoyue2)();

#program mark - 知识点复习

1.分类

1>是什么

当一个类中有很多属于不同范畴的方法的时候,通常使用分类来把这些方法进行分类,有一个类叫本类,其他的叫分类.

2>有什么特点?

1)和主类在一起共同构成了一个类

2)不能声明属性,只能添加方法

3)可以实现和主类同名的方法,编译的时候会覆盖主类的方法.如果调用此方法,调用分类的.

4)如果两个分类实现的方法名字相同,谁最后编译调用谁的.

5)主类肯定比分类先编译.

2.延展

1>什么是延展

延展也是一个分类,只不过这个分类和主类公用一个.m文件.并且延展是没有名字的

2)有什么特点

1)可以声明属性,也可以声明方法

2)一般是把类的延展写在主类的.m里,延展中声明的方法/属性,只能在当前类的内部使用,在当前类的外部无法访问

"例子

一个ViewController代表一个界面,内部的显示/内存管理由当前控制器类自己管理,外界不需要知道内部做了什么,此时控制器对象的一些属性方法,就可以写在控制器.m中的延展里

3.非正式协议

1>是什么?

就是给苹果提供的类写分类

"例子

NSString 添加分类 --->统计一个字符串对象内部阿拉伯数字个数

.h

@interface NSString (YYfenlei)

-(int)numOfAlaboSuzi;

@end

.m

-(int)numOfAlaboSuzi

{

//    self 就代表当前字符串对象

}

4.block变量的定义

//1.无参数无返回值block变量 xiaoyueblock

void (^xiaoyueBlock)();

//2.有一个int型参数返回值bint型的lock变量 xiaoyue2

int (^xiaoyue2)(int opNum);

//3.定义一个有三个参数,int,double,char,返回值是double类型的block 变量xiaoyue3

double (^xiaoyue3)(int opNum1,char opNum2,double opNum3);

"变量的赋值

1>int

int num;

num = 10;

2>函数的指针

int add(int a,int b);

int add(int a,int b)

{

return a+b;

}

//只是定义了一个函数的指针,还没有和任何函数关联

int (*p)(int a,int b);

//使用函数名给函数的指针赋值

p=add;

3>

//1.无参数无返回值block变量 xiaoyueblock

void (^xiaoyueBlock)();

xiaoyueBlock = ^void (){

代码;

};

//2.有一个int型参数返回值bint型的lock变量 xiaoyue2

int (^xiaoyue2)(int opNum);

xiaoyue2 = ^int (int opNum){

return opNum + 10;

};

//3.定义一个有三个参数,int,double,char,返回值是double类型的block 变量xiaoyue3

double (^xiaoyue3)(int opNum1,char opNum2,double opNum3);

xiaoyue3 = ^double(int opNum1,char opNum2,double opNum3){

return 1.1 + opNum2;

};

int main()

{

double dou =  xiaoyue3(2,'a',1.1);

return 0;

}

#program mark - 05 block变量的初始化和使用 [掌握]

此知识点的复习见OC加强03视频笔记/05 block变量的初始化和使用.pdf

#program mark - 06 block的简写 [听懂]

此知识点的复习见OC加强03视频笔记/06 block的简写.pdf

"强调

自己写的时候不要简写,能看懂别人的简写

"例子

//定义一个有三个参数,int,double,char,返回值是double类型的block 变量xiaoyue3

//完整写法

double (^xiaoyue3)(int opNum1,char opNum2,double opNum3)= ^double(int opNum1,char opNum2,double opNum3){

return 1.1 + opNum2;

};

//简化写法

double (^xiaoyue3)(int ,char,double )= ^(int opNum1,char opNum2,double opNum3){

return 1.1 + opNum2;

};

#program mark - 07 使用typedef简化block定义

此知识点的复习见OC加强03视频笔记/07 使用typedef简化block定义.pdf

"复习

//定义一个 Lint别名 代表long int 这种类型

typedef long int Lint;

//定义一个 arr别名 代表 长度是3的整型数组 这种类型

typedef int arr[3];

//定义一个 xiaoyue别名 代表 返回值是int,参数是空的block 这种类型

typedef  int (^xiaoyue)();

int main()

{

Lint num = 1000;

//定义一个长度是3的int型数组brr

arr brr = {1,2,3};

//定义一个返回值是int没有参数的变量

xiaoyue xiaoxiaoyue;

return 0;

}

"练习

利用typedef定义一个别名叫做hello的无参无返回值的block类型,定义一个hello类型block变量并调用

利用typedef定义一个别名叫做add的有两个int参数参无返回值的block类型,定义一个add类型block变量并调用

typedef  void (^hello)();

typedef  void (^add)(int opNum1,int opNum2);

int main()

{

hello xiaoyueblock1;

xiaoyueblock = ^void(){

NSLog(@"hello world!");

};

add xiaoyueblock2 = ^void(int opNum1,int opNum2){

NSLog(@"和是%d",opNum2+opNum1);

};

return 0;

}

#program mark - 08 block访问外部变量的问题 [掌握]

1.block类型的变量,可以定义变量的,

int main()

{

//无返回值有一个int参数block变量

void (^xiaoyuedashiBlock)(int opNum) =  ^void(int num1){

int num2 = 10;

num2++;

num1++;

NSLog(@"%d-----%d",num1,num2);

};

xiaoyuedashiBlock(22);

return 0;

}

2.block里面存代码内部是可以访问外部变量的.

//定义一个全局变量

int quanju_num = 10;

int main()

{

//无返回值有一个无参数block变量

void (^xiaoyuedashiBlock)();

//定局部变量

int jubu_num = 20;

xiaoyuedashiBlock =  ^void(){

NSLog(@"%d---%d",quanju_num,jubu_num);

};

xiaoyuedashiBlock();

return 0;

}

3.block内的代码可以修改全局变量,但是不能修改外部变量

//定义一个全局变量

int quanju_num = 10;

int main()

{

//无返回值有一个无参数block变量

void (^xiaoyuedashiBlock)();

//定局部变量

int jubu_num = 20;

xiaoyuedashiBlock =  ^void(){

//        quanju_num++;没问题

//        jubu_num++;编译报错

NSLog(@"%d---%d",quanju_num,jubu_num);

};

xiaoyuedashiBlock();

return 0;

}

4.block内的代码如果一定要"修改"外部变量,可以在定义这个变量的时候添加__block修饰这个变量

//定义一个全局变量

int quanju_num = 10;

int main()

{

//无返回值有一个无参数block变量

void (^xiaoyuedashiBlock)();

//定局部变量

__block int jubu_num = 20;

xiaoyuedashiBlock =  ^void(){

quanju_num++;

jubu_num++;

NSLog(@"%d---%d",quanju_num,jubu_num);

};

xiaoyuedashiBlock();

return 0;

}

5.为什么block内的代码可以修改全局变量,但是不能修改外部变量??

因为block

//定义一个全局变量

int quanju_num = 10;

int main()

{

//无返回值有一个无参数block变量

void (^xiaoyuedashiBlock)();

{

//定局部变量

__block int jubu_num = 20;

xiaoyuedashiBlock =  ^void(){

quanju_num++;

jubu_num++;

NSLog(@"%d---%d",quanju_num,jubu_num);

};

}

xiaoyuedashiBlock();

return 0;

}

#program mark - 09 block作为函数的参数

//定义一个函数无返回值参数是一个int型数据

void test1(int a)

{

a++;

printf("%d\n",a+10);

}

//定义一个参数是block的函数

void test( void (^xiaoyuedashiBlock)())

{

xiaoyuedashiBlock();

}

int main()

{

//把一个没有返回值的没有参数的block当做上面函数的参数

void (^youse)() =  ^void(){

NSLog(@"block执行了!");

};

test);

}

"练习

模拟IOS开发:

写一个无返回值的函数,函数名requestData

函数内有三个顺序执行的功能,发送网络请求,解析请求到的数据,展示数据,这三个功能用NSLog模拟.

函数要求有一个block参数,这个block里面的代码用来播放动画,这段代码必须在函数内解析数据后调用(播放动画也用NSLog模拟).

1.先写自己能做

1>定义函数

1)发送请求 NSLog

2)解析数据 NSLog

3)展示数据 NSLog

void requestData();

void requestData()

{

NSLog(@"发送请求");

NSLog(@"解析数据");

NSLog(@"展示数据");

}

2.实现函数参数的定义

void requestData(void (^dongHuang)());

void requestData(void (^dongHuang)());

{

NSLog(@"发送请求");

NSLog(@"解析数据");

dongHuang();

NSLog(@"展示数据");

}

3.实现调用

int main()

{

void (^donghuablock)() = ^void(){

NSLog(@"播放一个翻转动画");

};

requestData(donghuablock);

return 0;

}

"新需求

实现网络解析了多长时间就播放多久的动画

void requestData(void (^dongHuang)(double sec));

void requestData(void (^dongHuang)(double sec))

{

NSLog(@"发送请求");

NSLog(@"解析数据");//5s

dongHuang(9.0);

NSLog(@"展示数据");

}

int main()

{

void (^donghuablock)(double sec);

donghuablock = ^void(double sec){

NSLog(@"播放一个旋转动画播放%lf秒",sec);

};

requestData(donghuablock);

return 0;

}

#program mark -10 block作为方法的参数 [掌握]

此知识点的复习见OC加强03视频笔记/10 block作为方法的参数.pdf

"强调

block作为参数的理解的要点

block是一种数据类型,block这种数据类型的变量,里面存储的就是代码.

block变量中存储的是代码,这个block变量可以传来传去,只要拿到这个block变量,就能调用变量里面存放的代码.

#program mark -11  block作为方法的参数2 [掌握]

"复习

1.定义字符串的两种方式

1>数组方式

char str[] = {'a','b','\0'};

2>指针方式

char *str2 = "ab";

2.什么是指针数组

是数组,只不过这个数组中存放的是指针.

3.指针字符串数组

是数组,里面存的是用指针方式定义的字符串

char *str1 = "手机响了";

char *str2 = "她喜欢我";

char *str3 = "我能反杀";

char *arr[3] = {

str1,

str2,

str3,

};

4.strcmp(字符串1,字符串2)函数数的使用步骤和原理

1>引入<string.h>

2>从两个字符串的第一个字符开始比较,比较对应的ASCII码,一旦有结果了就停止

字符串1==字符串2时候结果0

字符串1>字符串2时候结果>0

字符串1<字符串2时候结果<0

#include<string.h>

int main()

{

char *str1 = "ab";

char *str2 = "cA";

int result =   strcmp(str1,str2);

printf("%d\n",result);

}

"需求

有一个指针字符串数组

char *countries[] =

{

"Nepal",

"Cambodia",

"Afghanistan",

"China",

"Singapore",

"Bangladesh",

"India",

"Maldives",

"South Korea",

"Bhutan",

"Japan",

"Sikkim",

"Sri Lanka",

"Burma",

"North Korea",

"Laos",

"Malaysia",

"Indonesia",

"Turkey",

"*",

"Pakistan",

"Philippines",

"Vietnam",

"Palestine"

};

1.定义函数把字符串按照大小排序

void paiXuWithASCII(char * countries[],int length)

{

char *temp = nil;

for (int i = 0; i < length - 1; i++) {

for (int j = 0; j < length - i -1; j++) {

if(strcmp(countries[j],countries[j+1])>0)

{

temp = countries[j];

countries[j] = countries[j+1];

countries[j+1] = temp;

}

}

}

for (int i  = 0; i < length; i++) {

printf("%s\n",countries[i]);

}

}

int main()

{

paiXuWithASCII(countries,24);

return 0;

}

2.定义一个函数,按照每个字符串长度排序

void paiXuWithASCII(char * countries[],int length)

{

char *temp = nil;

for (int i = 0; i < length - 1; i++) {

for (int j = 0; j < length - i -1; j++) {

if((int)strlen(countries[j])-(int)strlen(countries[j+1])<0)//用strlen表

{

temp = countries[j];

countries[j] = countries[j+1];

countries[j+1] = temp;

}

}

}

for (int i  = 0; i < length; i++) {

printf("%s\n",countries[i]);

}

}

int main()

{

paiXuWithASCII(countries,24);

return 0;

}

3.调用这个函数实现排序,按照调用者的要求排序

//分析:比较上面两种实现,两种功能之间唯一不同的代码,在排序循环中的if语句的判断条件部分,能否把if判断语句,传到函数中,实现根据不同的需求进行潘旭

//1.确定的是传入的肯定是if判断条件中,和下面两句代码类似的

if(strcmp(countries[j],countries[j+1])>0)

if(strlen(countries[j])-strlen(countries[j+1])<0)//用strlen表

//2分析传入的代码

//1>需要返回值吗--->需要 0/1

//2>需要参数吗? -->肯定要参数,countries[j],countries[j+1]

BOOL (^xiaoyuedashiBlock)(char * opXing1,char * opXing2) = ^BOOL(char * opXing1,char * opXing2){

BOOL result = ((int)strlen(opXing1)-(int)strlen(opXing2)<0)

return result;

};

4.修改函数

void paiXuWithUsrBlock(char * countries[],int length,BOOL (^xiaoyuedashiBlock)(char * opXing1,char * opXing2))

{

char *temp = nil;

for (int i = 0; i < length - 1; i++) {

for (int j = 0; j < length - i -1; j++) {

if( xiaoyuedashiBlock(countries[j],countries[j+1]))

{

temp = countries[j];

countries[j] = countries[j+1];

countries[j+1] = temp;

}

}

}

for (int i  = 0; i < length; i++) {

printf("%s\n",countries[i]);

}

}

int main()

{

BOOL (^xiaoyuedashiBlock)(char * opXing1,char * opXing2) = ^BOOL(char * opXing1,char * opXing2){

BOOL result = ((int)strlen(opXing1)-(int)strlen(opXing2)<0);

BOOL result2 = (strcmp(opXing1, opXing2)>0);

return result;

};

paiXuWithUsrBlock(countries,24,xiaoyuedashiBlock);

return 0;

}

#pragma mark 12 block与函数的异同 [掌握]

1.相同点

都是可以存储一段能够实现特定功能的代码

2.不同

1>block是一种数据类型,函数不是数据类型,函数就是一段代码

2>block可以直接做参数传递,函数是不可以的.函数的指针当参数传递本质是间接传递"了解一下

void test()

{

printf("xxx\n");

}

void (*p)() = test;

void useTest(void (*p)())

{

p();

}

int main()

{

useTest(p);

return 0;

}

3.block是可以做函数的返回值的.

1>定义一个无返回值,有一个int型参数的block变量

void (^xiaoyuedashiBlock)(int num) = ^void(int num){

NSLog(@"%d",num);

};

2>定义无返回值无参数的函数

void test()

{

}

3>希望上面函数返回一个block

typedef void (^xiaoyuedashiBlock)(int num);

xiaoyuedashiBlock test()

{

void (^xiaoyuedashiBlock)(int num) = ^void(int num){

NSLog(@"%d",num);

};

return xiaoyuedashiBlock;

}

//测试

int main()

{

xiaoyuedashiBlock b1 = test();

b1(2);

return 0;

}

注意:

1.一般我们不这样写.这样可阅读性太差.

2.当函数的返回值是block类型的时候,返回值类型必须要用typedef的形式给出,否则报错

//下面代码会报错

typedef void (^)(int num) test()

{

void (^xiaoyuedashiBlock)(int num) = ^void(int num){

NSLog(@"%d",num);

};

return xiaoyuedashiBlock;

}

#pragma mark 13 协议的基本使用 [掌握]

协议:@protocol

协议:专门用来写方法声明的,协议中不能写属性

遵守协议的类,这个类就拥有了这份协议中的所有方法的声明,而不用自己去定义