项目笔记
2019-07-30 本文已影响0人
苹果上的小豌豆
项目笔记
1. framework风格架构
-
独立的业务模块,或一个独立的功能模块,把它封装成 Framework,供上层调用。
-
如何创建 framework?
File -> New -> Project -> 选Cocoa Touch Framework -> 填写Product Name -> Add to: Name, Group: Name
2. Swift.Error枚举
- 举例
public enum FCNetworkError: Swift.Error {
case jsonMapping(response: Moya.Response)
case businessCode(json: SwiftyJSON.JSON, message: String?)
case attributeExists(json: SwiftyJSON.JSON, message: String?)
case networkError(code: Int, message: String?)
}
- 如上所示
3. Notification封装
- 代码如下:
public enum NotificationKeys: String {
case workOrderStatusChange = "WorkOrderStatusChange"
}
extension NotificationKeys {
private func name() -> Notification.Name {
return Notification.Name(rawValue: self.rawValue)
}
}
extension NotificationKeys {
public func post(object: Any? = nil, userInfo: [AnyHashable: Any]? = nil) {
NotificationCenter.default.post(name: self.name(), object: object, userInfo: userInfo)
}
public func addObserver(_ observer: Any, selector: Selector, object: Any? = nil) {
NotificationCenter.default.addObserver(observer, selector: selector, name: self.name(), object: object)
}
public func removeObserver(_ observer: Any) {
NotificationCenter.default.removeObserver(observer, name: self.name(), object: nil)
}
}
extension Notification.Name {
public func post(object: Any? = nil, userInfo: [AnyHashable: Any]? = nil) {
NotificationCenter.default.post(name: self, object: object, userInfo: userInfo)
}
public func addObserver(_ observer: Any, selector: Selector, object: Any? = nil) {
NotificationCenter.default.addObserver(observer, selector: selector, name: self, object:
object)
}
public func removeObserver(_ observer: Any) {
NotificationCenter.default.removeObserver(observer, name: self, object: nil)
}
}
-
调用方式:
NotificationKeys.workOrderStatusChange.post()
4. 压缩图片方法
///压缩图片上传
fileprivate func compressImageToSuitableSize(compressImage: UIImage, compressvalue compressionQuality: CGFloat = 0.8) -> Data? {
var actualHeight: CGFloat = compressImage.size.height
var actualWidth: CGFloat = compressImage.size.height
let maxHeight: CGFloat = kCompressImageInitDefaultMaxHeight
let maxWidth: CGFloat = kCompressImageInitDefaultMaxWidth
var imageRatio: CGFloat = actualWidth / actualHeight
let maxRatio: CGFloat = maxWidth / maxHeight
if actualHeight >= maxHeight || actualWidth >= maxWidth {
if imageRatio < maxRatio {
///根据最大高度来调整实际宽度
imageRatio = maxHeight / actualHeight
actualWidth = imageRatio * actualWidth
actualHeight = maxHeight
} else if imageRatio > maxRatio {
///根据最大宽度来调整实际高度
imageRatio = maxWidth / actualWidth
actualHeight = imageRatio * actualHeight
actualWidth = maxWidth
} else {
actualHeight = maxHeight
actualWidth = maxWidth
}
}
let rect = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight)
UIGraphicsBeginImageContext(rect.size)
compressImage.draw(in: rect)
guard let lastImage = UIGraphicsGetImageFromCurrentImageContext() else {
UIGraphicsEndImageContext()
return UIImageJPEGRepresentation(compressImage, compressionQuality)
}
guard let imageData = UIImageJPEGRepresentation(lastImage, compressionQuality) else {
UIGraphicsEndImageContext()
return UIImageJPEGRepresentation(lastImage, compressionQuality)
}
UIGraphicsEndImageContext()
return imageData
}
5. [Realm-Swift] 数据库的使用详解
总结一下:初始化创建实例对象,给对象赋值,数据持久化write写入,读取,删除,新增。
//用户头像
class HeadPortrait:Object {
//图片数据
@objc dynamic var data:Data?
//创建时间
@objc dynamic var date = Date()
}
do {
let data = try Data.init(contentsOf: url)
model.imageData = data
try Realm().write {
realm.add(model, update: true)
}
} catch let error {
Log("失败:\(error.localizedDescription)")
}
guard let model = realm.object(ofType: HeadPortrait.self, forPrimaryKey: "1") else {
return nil
}
do {
let realm = try Realm()
// 取已保存所有广告
guard let model = realm.object(ofType: HeadPortrait.self, forPrimaryKey: "1") else {
return nil
}
realm.beginWrite()
realm.delete(model)
try realm.commitWrite()
} catch let error {
Log("失败:\(error.localizedDescription)")
}
6. AppDelegate第三方注册启动优化和封装
在AppDelegate中,一个大型项目会有很多第三方key值注册,比如友盟统计,第三方登录,个推,地图注册 等等,我们需要做一个 扩展,将代码整理,便于后期的维护和优化
如下:

1.在AppDelegate中只需要如下:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow.init(frame: UIScreen.main.bounds)
window?.backgroundColor = UIColor.white
window?.makeKeyAndVisible()
self.performSetup(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
2.在扩展中进行下面的操作:
extension AppDelegate {
func performSetup(_ application: UIApplication, didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
/////umeng统计
//友盟分享注册
// 百度地图启动
// 埋点统计
}
3.开辟一个线程,耗时操作不要在AppDelegate启动的时候进行:
let backgroundQueue = DispatchQueue(label: "com.geselle.backgroundQueue", qos:
.background)
backgroundQueue.async {
//去做key的注册和第三方初始化
}
7.SnapKit的进阶
-
SnapKit的 dividedBy(除)、multipliedBy(乘)、offset(偏距)、inset 使用
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 64, left: 150, bottom: 500, right: 150))
-
equalTo()
-
lessThanOrEqualTo()
-
greaterThanOrEqualTo()
-
SnapKit通过view.safeAreaLayoutGuide
magentaView.snp.makeConstraints { (make) in make.top.equalTo(view.safeAreaLayoutGuide.snp.top) make.left.right.equalToSuperview() make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom) }
-
SnapKit可以通过属性
priority
来设置优先级
优先级顺序是:
required > high > medium > low
8.关于iOS相关动画
1.transform.translation.x
X轴循环滚动
let anim = CABasicAnimation.init()
anim.keyPath = "transform.translation.x"
anim.fromValue = self.bounds.origin.x
anim.toValue = self.bounds.origin.x - 100
anim.duration = CFTimeInterval(0.2)
anim.repeatCount = MAXFLOAT
anim.isRemovedOnCompletion = false
anim.fillMode = CAMediaTimingFillMode.forwards;
anim.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.linear)
Layer.add(anim, forKey: nil)
2. transform.translation.y
,Y轴循环滚动(Z轴,opacity)
let basicAnimation = CABasicAnimation(keyPath: "transform.translation.y")
basicAnimation.fromValue = userImageView.origin.y - 5
basicAnimation.toValue = userImageView.origin.y + 5
basicAnimation.duration = 1.5
basicAnimation.repeatCount = HUGE
basicAnimation.fillMode = CAMediaTimingFillMode.forwards
basicAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
View.layer.add(basicAnimation, forKey: nil)
3.动画的组合使用:
let animation = CASpringAnimation()
animation.keyPath = "position.y"
animation.fromValue = UIScreen.main.bounds.height
animation.toValue = cell.center.y
// 质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大
animation.mass = 1
// 刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快
animation.stiffness = 60
// 阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快
animation.damping = 10
// 初始速率
animation.initialVelocity = 0
animation.fillMode = .forwards
animation.isRemovedOnCompletion = false
let alphaAni = CABasicAnimation()
alphaAni.keyPath = "opacity"
alphaAni.fromValue = 0
alphaAni.toValue = 1
let group = CAAnimationGroup()
group.animations = [animation, alphaAni]
group.duration = animation.settlingDuration
group.fillMode = .forwards
group.isRemovedOnCompletion = false
cell.layer.add(group, forKey: "cell_reload")
比如另一个:
let appearAnim = CABasicAnimation(keyPath: "opacity")
appearAnim.delegate = self
appearAnim.duration = duration
appearAnim.fromValue = 0
appearAnim.toValue = 1
appearAnim.fillMode = .forwards
appearAnim.isRemovedOnCompletion = false
toView.layer.add(appearAnim, forKey: "toView_AppearAnim")
let pushPositionAnim = CABasicAnimation(keyPath: "position.y")
pushPositionAnim.duration = duration
pushPositionAnim.delegate = self
pushPositionAnim.fromValue = fromView.layer.position.y
pushPositionAnim.toValue = fromView.layer.position.y-120
pushPositionAnim.timingFunction = CAMediaTimingFunction(name: .easeOut)
pushPositionAnim.fillMode = .forwards
pushPositionAnim.isRemovedOnCompletion = false
fromView.layer.add(pushPositionAnim, forKey: "push_Anim")
4.常规的动画:
UIView.animate(withDuration: 0.15, delay: 0.0, options: .curveEaseOut, animations: {
}) { finshed in
}
UIView.animate(withDuration: 0.9, delay: delayTime, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .curveEaseInOut, animations: {
self.frame = originalFrame
}) { finished in
}
backView.transform = backView.transform.scaledBy(x: 0.5, y: 0.5)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0, options: .beginFromCurrentState, animations: {
self.backView.transform = .identity
self.backView.alpha = 1
self.alpha = 1
}) { (finish) in
}
5.第三方的框架:
- AMPopTip(提示动画)
- pop (Facebook的动画)
- TransitionButton(登录注册反馈的按钮动画)
- ESTabBarController(TabBar第三方,很多动画类型)
9.虚线的画法
private func drawDottedLine(_ view: UIView) {
let layer = CAShapeLayer()
layer.bounds = view.bounds
layer.position = CGPoint(x: view.width * 0.5, y: view.height)
layer.fillColor = UIColor.clear.cgColor
layer.strokeColor = UIColor(0xe5e5e5).cgColor
layer.lineWidth = view.height
layer.lineJoin = kCALineCapRound
layer.lineDashPattern = [NSNumber(value: 3), NSNumber(value: 1)]
let path = CGMutablePath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: view.width, y: 0))
layer.path = path
view.layer.addSublayer(layer)
}
10.PinLayout:一套极具新意,基于代码的布局框架库
【pinlayout】(https://github.com/layoutBox/PinLayout)
【pinlayout掘金文档】(https://juejin.im/entry/59349400570c35005b52e429)
11.利用RX做一些简单的按钮点击图片点击事件操作
-
Target Action(传统写法:)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) func buttonTapped() { print("button Tapped") }
-
通过 Rx 来实现:
button.rx.tap .subscribe(onNext: { print("button Tapped") }) .disposed(by: disposeBag)
-
或者
orderBtn.rx.tapGesture().when(.recognized).subscribe(onNext: { [weak self] (_) in print("button Tapped") }).disposed(by: rx.disposeBag)
-
总结一下,我们可以在通知,点击事件Target Action,闭包回调,代理,多个任务之间有依赖关系,等待多个并发任务完成后处理结果,使用简单的RX。
-
如下举例1.通知:
NotificationCenter.default.rx .notification(.UIApplicationWillEnterForeground) .subscribe(onNext: { (notification) in print("Application Will Enter Foreground") }) .disposed(by: disposeBag)
-
如下举例2.textfiled监听:
inputField.rx.text.orEmpty.asObservable().subscribe(onNext: { [weak self](value) in self?.confirmBtn.isEnabled = value.count > 0 ? true : false }).disposed(by: rx.disposeBag)
-
如下举例3.UITextView监听:
self.rx.observeWeakly(UITextView.self, "text").subscribe(onNext: { [weak self](_) in self?.textValueChange() }).disposed(by: rx.disposeBag)
-
如下举例4.scrollView.delegate监听:
scrollView.rx.contentOffset .subscribe(onNext: { contentOffset in print("contentOffset: \(contentOffset)") }) .disposed(by: disposeBag)