美文网首页
完整Swift项目(模拟微博)演练、二

完整Swift项目(模拟微博)演练、二

作者: 下班不写程序 | 来源:发表于2020-04-01 11:37 被阅读0次

我将整个项目的复习拆分成了几个部分, 每完成一部分我都会提交一次代码, 大家根据所复习到的部分, 检出对应的分支来看代码就可以了, 代码中的注释已经十分详尽了, 有问题或者疑惑大家可以随时留言沟通.
项目地址

涵盖的知识点:
1.loadView的复习、loadView,viewDidLoad,viewDidUnload三者之间的联系
2.Swift下设置约束(原生/SnipKit)
3.核心动画的复习
4.iOS-单例的正确写法
5.iOS-Swift 和Objective-c 混编
6.自定义封装网络请求 Alamofire
7.模态带有导航栏的控制器

知识点1. loadView
     1. 什么时候被调用?
        -- 每次访问UIViewController的view(比如controller.view、self..view)而且view为nil,loadView方法就会被调用。控制器的view是懒加载的,什么时候使用,什么时候才创建, 如果已经创建,怎么调用都不会再创建了。
     2. 作用:创建控制器的view
     3. loadView执行逻辑:
        -- 3.1 当前控制器是否从StoryBoard当中加载, 如果是,就加载storyboard中的view
        -- 3.2 有没有xib来描述控制器的view,如果有,就加载xib当中的view
        -- 3.3 如果都不是,就用UIView 创建一个
     4. loadView,viewDidLoad,viewDidUnload三者之间的联系
        - 4.1 第一次访问UIViewController的view时,view为nil,然后就会调用loadView方法创建view
        - 4.2 view创建完毕后会调用viewDidLoad方法进行界面元素的初始化
        - 4.3 当内存警告时,系统可能会释放UIViewController的view,将view赋值为nil,并且调用viewDidUnload方法
        - 4.4 当再次访问UIViewController的view时,view已经在3中被赋值为nil,所以又会调用loadView方法重新创建view
        - 4.5 view被重新创建完毕后,还是会调用viewDidLoad方法进行界面元素的初始化
知识点2. Swift下设置约束

注意:
1.代码addSubview, 如果想使用相对布局, 记得要设置subView 的translatesAutoresizingMaskIntoConstraints 为false, 否则会有autoresize 生成的constraints , 导致冲突, 也就是代码设置的约束不管用了.
2.而在Interface Builder 中Use autoLayout, IB 生成的控件的translatesAutoresizingMaskIntoConstraints 自动就被置位false了.
3.第三方约束工具SnipKit 自动帮助我们设置了.

2.1 系统原生设置约束的方法:

/** addConstraints参数说明:
  参数1: 添加约束的对象
  参数2: 添加约束的对象的哪个属性
  参数3: 约束关系
  参数4: 设置约束参考的对象
  参数5: 设置约束参考的对象的哪个属性
  参数6: 倍数
  参数7: 偏移量
*/
addConstraints([NSLayoutConstraint(item: feedImageView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0)])

2.2 第三方框架SnipKit (和OC 下的Masonry 一样)

  addSubview(maskImageView)
  maskImageView.snp_makeConstraints { (make) in
    make.center.equalTo(self)
  }

注: 添加约束的时候尽量不要写在layoutSubViews中, Swift会报错, 因为layoutSubViews会被多次调用, 所以多次添加约束, 就报错了. OC条件下是可以的.

知识点3. 核心动画习下的isRemovedOnCompletion属性
    // 设置 首页圆圈图片做动画
    private func setFeedImageViewAnim() {
        // 核心动画
        let anim = CABasicAnimation(keyPath: "transform.rotation")
        // 设置toValue
        anim.toValue = Double.pi * 2
        // 设置时长
        anim.duration = 20
        // 设置重复次数
        anim.repeatCount = MAXFLOAT
        // 默认是YES, 代表动画执行完毕后就从图层上移除, 图形就恢复到动画执行前的状态. 当切换控制器或者前后台时, 默认动画会被移除 -> 这里阻止这个操作
        anim.isRemovedOnCompletion = false
        // 添加动画
        feedImageView.layer.add(anim, forKey: nil)
    }
知识点4. OC 中的单例(可参考: iOS-单例的正确写法)
OC 中的单例.png
知识点5. Swift 中的单例 (static全局访问点) (可参考: iOS-单例的正确写法)
Swift 中的单例
知识点6. iOS-Swift 和Objective-c 混编
知识点7. 自定义封装网络请求 Alamofire
import UIKit
import Alamofire

/// Swift 中枚举不仅支持Int 类型, 还支持字符串和其它基本类型等
enum RequestMethod: String{
    case get = "get"
    case post = "post"
}

class HNetworkTools: NSObject {

    /// 定义全局的网络访问点
    static let shared: HNetworkTools = {
        let tools = HNetworkTools()
        return tools
    }()
    
    // MARK: 定义网络请求的公共方法
    func request(urlString: String, method: RequestMethod, parameters: Any?, success: @escaping (Any?)->(), failure: @escaping (Any?)->()) {
        
        Alamofire.request(urlString, method: getRequestMethod(method: method), parameters: parameters as? Parameters, encoding: URLEncoding.default, headers: nil).responseJSON { (response) in

            switch response.result {
            case .success(let json):
                success(json)
            case .failure(let error):
                debugPrint(error.localizedDescription)
                failure(error)
            }
        }
    }
    
    // MARK: 获取网络请求方式
    private func getRequestMethod(method: RequestMethod) -> (HTTPMethod) {
        
        if method == .get {
            return HTTPMethod.get
        } else {
            return HTTPMethod.post
        }
    }
}

注1: Swift 中枚举不仅支持Int 类型, 还支持字符串和其它基本类型等
注2: Alamofire.request 得到的结果类型为DataRequest; DataRequest.responseJSON 得到的类型是DataResponse.
注3: 上段代码中.success(let json)或者.failure(let error)可能会难以理解, 点击response.result 的result 我文件中就一目了然了.

public struct DataResponse<Value> {
    ...
    /// The result of response serialization. 响应序列化的结果。
    /// 点击Result 跳转至头文件, 是一个枚举类型->也就是success 和failure
    public let result: Result<Value>

    /// Returns the associated value of the result if it is a success, `nil` otherwise. 如果成功,则返回结果的关联值,否则返回“nil”。
    /// 其实就是你想得到数据信息, 如果success 时, 就通过上面.success(value), 将得到的信息传递出去; 如果failure,  就通过下面. failure(value), 将得到的错误信息传递出去.
    public var value: Value? { return result.value }

    /// Returns the associated error value if the result if it is a failure, `nil` otherwise. 如果结果为失败,则返回关联的错误值,否则返回“nil”。
    public var error: Error? { return result.error }
}
知识点8. 模态带有导航栏的控制器
    func present() {
        
        let presentVc: UIViewController = UIViewController()
        presentVc.view.backgroundColor = HRandomColor()
        // 这里可以修改 presentVc被推出的形式, 或者转场动画
        presentVc.modalPresentationStyle = .fullScreen
        presentVc.modalTransitionStyle = .coverVertical
        self.present(HNavigationController(rootViewController: presentVc), animated: true) {
            print("模态带有导航栏的控制器")
        }
    }

.End

相关文章

网友评论

      本文标题:完整Swift项目(模拟微博)演练、二

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