测试某个网址是否使用https:nscurl --ats-diagnostics --verbose https://www.baidu.com
Swift对象拷贝
Swift对象拷贝
方法一:实现NSCopying协议
1 | class Resume: NSObject, NSCopying { |
使用:let ben = Resume.init(name: "本初")
var shu = ben.copy() as! Resume
方法二:实现自定义拷贝协议
1 | protocol Copyable { |
使用:let sanguo = Book.init(name: "three of kingdom")
let book = sanguo.copied()
Swift实现removeObject
Swift实现removeObject
如果类没有继承自NSObject,那么类必须要实现Equatable
协议.否则不需要.
1 | class Observer { |
然后在通过扩展给Array增加一个removeObject(object: Element)
方法:
1 | extension Array where Element: Equatable { |
由于Array是结构体类型,而removeObject函数会改变结构体的值,所以该函数需要添加mutating关键字.“Notice the use of the mutating keyword in the declaration of SimpleStructure to mark a method that modifies the structure. The declaration of SimpleClass doesn’t need any of its methods marked as mutating because methods on a class can always modify the class.”
Swift addTarget函数的Selector参数
Swift里addTarget函数里的Selector参数和OC的不太一样.open func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControlEvents)
根据Selector的定义
1 | public struct Selector : ExpressibleByStringLiteral { |
它是一个结构体,并遵守ExpressibleByStringLiteral
协议,因此可以直接传递一个字面值字符串.
不过这个字符串需要遵循一定的规则:
- 如果函数没有参数,则字符串的格式为”函数名”.
- 如果函数有参数但省略了参数标签,则字符串的格式为”函数名:”.
- 如果函数有参数并且没有省略参数标签,则字符串的格式为”函数名With参数标签:”.ps:如果函数使用的是默认参数标签即使用参数名称作为参数标签的,那么字符串的格式为”函数名With参数名称:”
举个例子:
- 没有参数对应写法:
1
2func numberSliderChanged() -> Void {
}numberSlider.addTarget(self, action: "numberSliderChanged", for: .valueChanged)
- 省略参数标签对应写法:
1
2
3func numberSliderChanged(_ sender: UISlider) -> Void {
print("---", sender.value)
}numberSlider.addTarget(self, action: "numberSliderChanged:", for: .valueChanged)
- 写明了参数标签slider.对应写法:
1
2
3func numberSliderChanged(slider sender: UISlider) -> Void {
print(sender.value)
}numberSlider.addTarget(self, action: "numberSliderChangedWithSlider:", for: .valueChanged)
- 使用默认参数标签对应写法:
1
2
3func numberSliderChanged(sender: UISlider) -> Void {
print("sds", sender.value)
}numberSlider.addTarget(self, action: "numberSliderChangedWithSender:", for: .valueChanged)
然而这种写法已经废弃,目前swift3.1推荐的是使用#selector
,因此上述4写法等价于:numberSlider.addTarget(self, action: #selector(numberSliderChanged(sender:)), for: .valueChanged)
.
当然你也可以传递一个Selector类型的变量:numberSlider.addTarget(self, action: Selector.init(stringLiteral: "numberSliderChangedWithSender:"), for: .valueChanged)
.不过这种写法依然不是推荐的写法.
Swift协议
协议
可选实现
Swift里标记某个方法为可选实现时,需要在协议前添加@objc
,并且在可选方法前添加@objc optional
.其实也是为了跟OC兼容.
eg:
1 | @objc protocol Iterator { |
判断某个实例是否实现了协议里的可选方法:
1 | if i.isDone?() != nil { |
因为isDone是可选实现方法,所以调用时需要加?,这样就转为optional chaining处理,如果方法的返回值不为nil,则说明对象实现了协议的可选实现方法.
CocoaPods常见问题
Q:在用 Cocoapods 做第三方开源库管理的时候,有时候发现查找到的第三方库版本低于github上仓库的最新release版本.
A:执行pod update
更新本地仓库,完成后,即可搜索到指定的第三方库.
Q:在使用了pod setup
之后,发现好长时间都没有变化,无法从终端上获取pod setup
的执行情况.
A:这时候可以command+N新建一个窗口,通过sudo ls
用管理员权限查看目录,然后cd .cocoapods
文件夹,输入du -sh
命令查看文件夹大小变化,从而确定pod setup
的运行情况.
note:在Podfile文件中的platform :ios, '7.0'
,如果你设置的iOS系统过低,可能有的第三方库会下载不下来.所以还是要看一下第三方库的最低版本支持说明.
Q:RuntimeError - [Xcodeproj] Unknown object version.然后是一大堆错误日志.不管是重新从svn checkout一份新的还是怎样,pod install都不能成功.
A:一种解决办法:重新安装cocoapods.
Q:pod search xxx,总是失败,提示CDN: trunk URL couldn’t be downloaded … Response: SSL connect error
1 | [!] CDN: trunk Repo update failed - 2 error(s): |
解决办法:
The workaround to get working locally during this outage or CDN issue - guessing a DNS change or something?:
1 | pod repo remove trunk |
In Podfile
can't find gem cocoapods (>= 0.a)
更新ruby后,pod install出错.
xuequandeiMac:KingDynastyGaming xuequan$ pod install
提示:
1 | /Library/Ruby/Site/2.0.0/rubygems.rb:270:in `find_spec_for_exe': can't find gem cocoapods (>= 0.a) (Gem::GemNotFoundException) from /Library/Ruby/Site/2.0.0/rubygems.rb:298:in `activate_bin_path' from /usr/local/bin/pod:22:in `<main>' |
解决办法:卸载cocoapods后重新安装
- sudo gem uninstall cocoapods
- gem install cocoapods
- pod install
多个targets的Podfile写法
多个targets的Podfile写法
项目里面添加了多个target,每次pod install后,其他target就出现找不到#import <AFNetworking.h>
这样的编译错误,花了三个多小时才找到了原因:是因为Podfile文件只给其中一个target配置了,所以导致了上述的问题.
正确写法:
1 | platform :ios, '8.0' |
UITableView-FDTemplateLayoutCell源码分析
高度的计算
通过从可重用队列里出列一个cell,并将该cell配置好要展示的数据后(ps:在使用时如果有一些会影响cell高度的代码没有包括在配置block里将导致计算不准),开始计算cell的高度:
给cell添加约束:
NSLayoutConstraint *widthFenceConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:contentViewWidth];
对于10.2以上系统还需添加cell上下左右的约束:1
2
3
4
5
6
7
8
9
10
11
12if (isSystemVersionEqualOrGreaterThen10_2) {
// To avoid confilicts, make width constraint softer than required (1000)
widthFenceConstraint.priority = UILayoutPriorityRequired - 1;
// Build edge constraints
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeRight multiplier:1.0 constant:accessroyWidth];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
edgeConstraints = @[leftConstraint, rightConstraint, topConstraint, bottomConstraint];
[cell addConstraints:edgeConstraints];
}调用系统API
systemLayoutSizeFittingSize
计算出高度:fittingHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
移除之前添加的约束:
1
2
3
4[cell.contentView removeConstraint:widthFenceConstraint];
if (isSystemVersionEqualOrGreaterThen10_2) {
[cell removeConstraints:edgeConstraints];
}
最终得到cell的高度.
高度缓存的实现
通过给UITableView增加一个类别(FDIndexPathHeightCache)
:
1 | @interface UITableView (FDIndexPathHeightCache) |
类别里有一个FDIndexPathHeightCache
类型的属性fd_indexPathHeightCache
是只读的,用于操作缓存:设置缓存,取出缓存,清除缓存,查询某个缓存是否存在等.FDIndexPathHeightCache
内部扩展定义了一个用于保存缓存的二维数组.以后取缓存时是从该二维数组取得.默认高度是-1,即该行cell还未缓存高度.
缓存高度的清除时机
定义了一个类别FDIndexPathHeightCacheInvalidation
,该类别通过method swizzle交换了一些系统方法的实现.
数值计算
四舍五入保留两位小数
NSString *strOdds = [NSString stringWithFormat:@"%.2f", odds]; //保留两位小数
该方法会四舍五入保留两位小数,不足两位小数后面补0.如果想在四舍五入时去掉小数点后多余的0,可使用下面的方法:
1 | - (NSString *)roundingAfterPoint:(NSInteger)position roudingMode:(NSRoundingMode)roundingMode |
调用:NSString *rs = [self roundingAfterPoint:2 roudingMode:NSRoundPlain];
在进行浮点型数值计算时最好统一类型,比如全部统一为float计算,或全部为double型计算.否则可能会出现误差,导致计算不一致.
浮点型数值取整
- round:如果参数是小数,则求本身的四舍五入。
- ceil:如果参数是小数,则求最小的整数但不小于本身.
- floor:如果参数是小数,则求最大的整数但不大于本身.
Example:如果值是3.4的话,则round 3.000000, ceil 4.000000, floor 3.00000
另外,强制取整(int)3.4 = 3
,直接丢弃小数位仅保留整数位,类似于floor函数.