#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
协议:专门用来写方法声明的,协议中不能写属性
遵守协议的类,这个类就拥有了这份协议中的所有方法的声明,而不用自己去定义