美文网首页
项目笔记

项目笔记

作者: 苹果上的小豌豆 | 来源:发表于2019-07-30 14:25 被阅读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值注册,比如友盟统计,第三方登录,个推,地图注册 等等,我们需要做一个 扩展,将代码整理,便于后期的维护和优化

如下:

image.png
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.xX轴循环滚动

 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)

相关文章

网友评论

      本文标题:项目笔记

      本文链接:https://www.haomeiwen.com/subject/kcqfrctx.html