iOS学习 - CocoaPods & 传值常用技术
- 学习日期:2021 - 12 - 18
- 署名:SSR
CocaoPods
介绍
-
是什么: 管理iOS项目的依赖管理器
-
使用的语言:
Ruby -
目的: 自动安装/更新第三方依赖库
-
为什么: 没有之前,只能手动往项目导入第三方库
拷贝源码 => 添加framwork =>设置BuildPhase
-
优点:
- 中心化的配置:
所有依赖的第三方库都写在Podfile里,便于管理。 - 便于更新:
中心化的配置,只需要Podfile中更新版本号 - 一件集成:
只需执行pod install,就能自动安装所有依赖库 - 自动处理依赖:
CocoaPods会自动安装第三方依赖库
- 中心化的配置:
Ruby
-
是什么: 一种简单快捷的面向对象的脚本语言
-
扩展性: 可运行于多钟平台
-
特点:
- 完全面向对象:
任何东西都是对象,基本类型也是对象 - 变量没有类型:
可以保存任何类型数据 - 任何东西都有值:
数学、逻辑表达式、句子 都会有值
- 完全面向对象:
-
使用工具:
RVM(全名: Ruby Version Manager)- 命令行工具:
提供一个便捷的多版本Ruby环境的管理和切换
- 命令行工具:
-
依赖: Ruby Project 依赖于一系列的 Ruby Gems
- 管理: 用
Bundler为Ruby Project提供统一构建环境
- 管理: 用
-
RubyGems(简称: Gems)
-
作用: 可以轻松下载,安装和使用系统上的
Ruby软件包 -
Ruby软件包(Gem)
-
是什么: 是
Ruby模块(Gems)的包管理 -
构建: 依照
.gemspec文件构建的 -
包含:
YAML文件、应用程序和库 -
功能: 与
apt-get、portage、yum、npm相似
-
-
依赖文件(Gemfile)
- 是什么: 描述Gems之间依赖的文件
- 定义:
从哪个 源 找到这些Gems、Gems的版本
-
CocoaPods 安装/更新
-
问题分析
为避免不同电脑的CocaPods版本不一样而导致的冲突
Bundller给出了更好的解决方案 -
步骤
- 创建一个
Gemfile文件,输入:
source 'https://rubygems.org' do gem 'cocoapods', '1.5.0' end-
执行
bundle installbundler会根据Gemfile内容创建Gemfile.lock文件此文件要放入git等版本控制中,同时会下载
Gemfile中指定的版本 -
执行
bundle exec pod installbundler会检查按需下载安装相应版本的CocoaPods并进行pod install操作
- 创建一个
Podfile
- 是什么: 是一个描述了项目的具体依赖关系文件(使用Ruby语言)
- 编写Podfile文件:
platform :ios, '10.0' #基于iOS 10.0版本
#原型 platform(:ios, '10.0')
#:ios 这种语法在 Ruby 中叫符号(Symbol)。
#Ruby 区分了符号和字符串,符号内容不可变,字符串内容可变。
#因为符号内容并不可变,假如它们内容相同,就是同一个对象,共用同一份内存;
#但是字符串可变,就算它们内容相同,也是分离的两个对象。
#在 Ruby 中经常使用符号,特别是作为字典的 key。
use_frameworks!
#原型 use_frameworks!()
#Ruby 的函数参数可以有默认值。这里不传参数,flag 就默认为 true。
#Ruby 的名字可以带感叹号 !,表示强调,需要特别注意或者有某种危险。
#Ruby 的名字也可以带问号 ?,表示某种疑问。
#source '资源来源'
source 'https://github.com/CocoaPods/Specs.git'
#target '项目名称' do
# pod '库名' //导入第三方库
# pod '库名', '~>版本号' //规定导入版本号的第三方库
#end
#本质 构成了一个Block
target 'SSRApp' do
pod 'Masonry'
pod 'AFNetworking'
#target "测试项目Tests" do
target "SSRAppTests" do
inherit! :search_paths
pod 'OCMock', '~>2.0.1'
end
end
传值常用技术
传值一般有 属性、block、协议/代理、消息通知传值
属性传值
-
在被需要值的类的头文件中,将被需要的值暴露给外部使用
-
优点: 方便快捷
-
缺点: 容易被改写
最好用readonly
block
-
基础知识
-
组成部分以及实现
返回值类型 (^函数名) (函数参数) = (返回值) (^) (函数参数) {代码;};
-
调用: 若有返回值,则用相应类型去接收
函数名 (函数参数);
-
注意的点:
-
循环引用: 相互持有对方,造成两者无法释放,引起内存泄漏问题。
解除方式: 将任意一方引用 (__weak) ,解除相互持有
-
改变block捕获变量的值:
使用__block
-
-
-
作为参数
-
使用场景: 网络请求等耗时操作
需要对当得到一大串数时所使用操作
用于一些信息或错误等处理
-
使用例子:
基于命令行,用户输入两个整数,写一个类方法去判断是不是质数,写一个类方法去遍历[a ,b]中的所有质数转交回去,实现将质数平方后输出
SSR-block-质数的平方为:x,并且返回个数。错误反馈: 创建enum枚举出
找不到区间、后者为负数情况,并交回处理。//NSNumber+Prime.h #import <Foundation/Foundation.h> typedef NS_ENUM(NSInteger,PrimeInterval){ PrimeIntervalNoInterval,//找不到区间(区间写反了) PrimeIntervalNegativeNumber//后者为负数 }; @interface NSNumber(Prime) + (BOOL)isPrime:(int)number; + (int)countFrom:(int)begin to:(int)end seccess:(void)(^primeSeccess)(int prime) error:(void)(^primeError)(PrimeInterval error); @end//NSNumber+Prime.m @impletmentation NSNumber(Prime) + (BOOL)isPrime:(int)number{ if(number <= 1) return NO; for(int i = 2; i*i <= number; i++) if(number % i == 0) return NO; return YES; } + (int)countFrom:(int)begin to:(int)end seccess:(void)(^primeSeccess)(int prime) error:(void)(^primeError)(PrimeInterval error){ if(end <= begin){ primeError(PrimeIntervalNoInterval); return 0; } if(end <= 0){ primeError(PrimeIntervalNoInterval); } int sum = 0; for(int i = begin; i <= end; i++) if([NSNumber isPrime:i]){ sum++; primeSeccess(i); } return sum; } @end//main.c #import <Foundation/Foundation.h> #import "NSNumber+Prime.h" int main() { void (^success)(int prime) = ^(int prime){ NSLog(@"SSR-block-质数的平方为:%ld", prime * prime); } void (^error)(PrimeInterval errorNum){ switch(PrimeInterval){ case PrimeIntervalNoInterval: NSLog(@"无此区间/区间写反了"); break; case PrimeIntervalNegativeNumber NSLog(@"后者为负数,不存在质数"); break; default: NSLog(@"未知错误!!!"); } } //测试1:输入 较小正数 较大正数 NSLog(@"测试1:从23到100") int sum1 = [NSNumber countFrom:23 to:100 seccess:seccess error:error]; NSLog(@"总数为:%d",sum1); //测试2:输入 较大正数 较小正数 NSLog(@"测试2:从100到23") int sum2 = [NSNumber countFrom:100 to:23 seccess:seccess error:error]; NSLog(@"总数为:%d",sum2); //测试3:输入 负数 1 NSLog(@"测试3:从-23到1") int sum3 = [NSNumber countFrom:-23 to:1 seccess:seccess error:error]; NSLog(@"总数为:%d",sum3); //测试4:输入 负数 较大正数 NSLog(@"测试1:从-23到100") int sum4 = [NSNumber countFrom:-23 to:100 seccess:seccess error:error]; NSLog(@"总数为:%d",sum4); //测试5:输入 正数 负数 NSLog(@"测试5:从23到-23") int sum5 = [NSNumber countFrom:23 to:-23 seccess:seccess error:error]; NSLog(@"总数为:%d",sum5); return 0; }
-
-
block作为属性
-
当其他类访问时,可以直接通过属性
点出来优点: 方便快捷
缺点: 暴露在外面
-
使用例子
SSR商品有商品名字,单价,数量,股值(单价*数量)
当用户买了过后,股值发生变化,数量相应减少
当没有货物时,应告诉用户你还差购买的商品数
//SSRCommodity.h #import <Foundation/Foundation.h> @interface SSRCommodity:NSObject @property (nonatomic, copy, readonly) float totalPrices; + (instancetype) initWithName:(NSString *)name price:(float)price amount:(NSUInterger)amount; - (NSUInterger)amountAfterSelledWithAmount:(NSUInterger)amount success:(void(^)(NSUInterger make)makemoney) errorEmpity:(void(^)(NSUInterger remain)empity); @end//SSRCommodity.m #import "SSRCommodity.h" @interface SSRCommodity () @property (nonatomic, strong) NSString *name; @property (nonatomic) float price; @property (nonatomic) NSUInteger amount; @end @implementation SSRCommodity + (instancetype) initWithName:(NSString *)name price:(float)price amount:(NSUInteger)amount{ if(self = [super init]){ _name = name; _price = price; _amount = amount; _totalPrices = price * amount; } return self; } - (NSUInterger)amountAfterSelledWithAmount:(NSUInterger)amount success:(void(^)(NSUInterger make)makemoney) errorEmpity:(void(^)(NSUInterger remain)empity){ if(amount <= self.amount){ _amount -= amount; _totalPrices = price * amount; makemoney(amount * price); } else{ amount -= _amount; _amount = 0; _totalPrices = 0; empity(amount); } return _amount; } @end//main.h #import <Foundation/Foundation.h> #import "SSRCommodity.h" int main() { SSRCommodity *shoes = [SSRCommodity initWithName:@"Adidas" price:2999 amount: 366]; NSLog(@"股值:%ld",shoes.totalPrices); NSLog(@"Day-1:卖出:200件,记录如下:"); NSUInterger made1 = [shoes amountAfterSelledWithAmountt:200 success:((^)(NSUInterger make){ NSLog(@"\t赚得:%ld",make); }) errorEmpity:(void(^)(NSUInterger remain)empity){ NSLog(@"\t卖空了,你还差%ld件未买到", empity); }]; NSLog(@"\t仓库还剩数量:%ld\n\t股值:%ld", made1, shoes.totalPrices); NSLog(@"Day-2:卖出:300件,记录如下:"); NSUInterger made2 = [shoes amountAfterSelledWithAmount:300 success:((^)(NSUInterger make){ NSLog("赚得:%ld",make); }) errorEmpity:(void(^)(NSUInterger remain)empity){ NSLog("卖空了,你还差%ld件未买到", empity); }]; NSLog(@"\t仓库还剩数量:%ld\n\t股值:%ld", made2, shoes.totalPrices); return 0; }
-
通知中心
-
是什么: 由发送者1或者多个发送者n,
通过发送一个通知到通知中心,
接收者1或者多个接收者都可以接收到发送过来的通知 -
使用场景
- 两个毫无关系的类之间进行交互操作
- 对于一些必要的,对于系统活动的监听(如键盘弹起、收回时机)
-
属性
-
这个消息的名字(唯一标识),用于辨别消息对象。(可以看成是消息频道)@property (readonly, copy) NSNotificationName name; -
发送的对象,即这个消息只发送给某一个对象@property (nullable, readonly, retain) id object; -
字典,作用是传递各种各样的值@property (nullable, readonly, copy) NSDictionary *userInfo;
-
-
创建
-
通知中心是单例
每一个应用程序会有一个默认的通知中心。用于调度通知发送和接受。
-
创建代码
NSNotificationCenter *ncc = [NSNotificationCenter defaultCenter];注意: 不能使用
init进行初始化
-
-
注册通知
-
作用: 可以为观察者指定一个方法,名字,对象。接受到通知时,便执行方法。
-
代码定义
- (void) addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject -
参数介绍
(id)observer:观察者(注册者)(SEL)aSelector:当观察者接受到通知时执行的方法(NSString *)aName:通知的名字(id)anObject:限定被通知的对象
-
-
发送通知
-
代码定义
- (void) postNotification:(NSNotification *)notification; - (void) postNotificationName:(NSString *)aName Object:(id)anObject; - (void) postNotificationName:(NSstirng *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo; -
参数介绍
(NSNotification *)notification:通知对象(本质是第三个代码参数的对象化)(NSString *)aName: 消息名字(频道)(id)anObject: 接受固定对象的通知,nil时接受所有对象发送该消息名的消息(NSDictionary *)aUserInfo: 发送消息时传递的各种值
-
-
移除通知
-
代码定义
- (void)removeObserver:(id)observer; - (void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject -
介绍
removeObserver:直接移除掉这个观察者,这个观察者上注册的所有通知都作废removeObserver:name:object:只移除这个观察者某个通知
-
-
注意点
-
通知中心注册时的方法(
(SEL)aSelector)必须要实现,不实现会崩溃 -
书写通知中心代码
- viewWillApperar中注册,viewWillDisappear中移除,减少对于性能的影响
- viewDidLoad中注册。如果在viewWillApperar中注册却没有在viewWillDisappear中移除那么会造成注册很多次,可能会造成一个事件触发后被多次响应。
-
通知中心很强大,但对
性能的影响、代码的整洁性和协作开发来说,通知中心永远作为备选。
-