简述:swift
语法看的差不多后,就写了个简单的项目架构(其中涉及的语法还是很多的),一写起来,就感觉swift
赏心悦目有木,虽说有些地方很晦涩,但是熟悉起来就好了,建议学swift
还是先研究语法,这样上手会轻松很多,下面上代码
关于代码里面涉及的语法就不啰嗦了,大家根据自己所学对照验证
- UITabBarController
LZ
用的是读取info.plist
方式获取tabBarItem
配置信息
class NJF_TabBarViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
let itemUrl: String? = Bundle.main.path(forResource: TabBarItemInfo, ofType: nil)
if itemUrl == nil {return}
let dictItemArr: NSArray? = NSArray(contentsOfFile: itemUrl!)
if dictItemArr == nil {return}
dictItemArr?.enumerateObjects({ (obj, idx, stop) in
//校验
guard let itemDict = obj as? [String : NSObject] else {return}
let clsN: String = itemDict["vc"] as! String
let cls: AnyClass? = classFromCls(clsN)
if cls == nil {return}
let vcCls = cls as! UIViewController.Type
let vc = vcCls.init()
addChildVC(vc, itemTitle: itemDict["title"] as! NSString, imageN: itemDict["normalImgeName"] as! NSString, selImageN: itemDict["selImgeName"] as! NSString)
})
}
}
extension NJF_TabBarViewController {
fileprivate func addChildVC(_ vc: UIViewController, itemTitle: NSString, imageN: NSString, selImageN: NSString) {
var image : UIImage = UIImage(named: imageN as String)!
var selImage : UIImage = UIImage(named: selImageN as String)!
image = image.withRenderingMode(UIImage.RenderingMode.alwaysOriginal);
selImage = selImage.withRenderingMode(UIImage.RenderingMode.alwaysOriginal);
vc.tabBarItem = UITabBarItem.init(title: itemTitle as String, image: image, selectedImage: selImage)
//改变字体颜色
vc.tabBarItem.setTitleTextAttributes([NSAttributedString.Key.foregroundColor: UIColor.init(r: 255, g: 211, b: 59)], for:.selected)
vc.title = itemTitle as String
let nav = NJF_NavigationViewController(rootViewController: vc)
addChild(nav)
}
}
- UINavigationController
class NJF_NavigationViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
initializeSet()
}
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
//隐藏底部tabBar
if viewControllers.count > 0 {
viewController.hidesBottomBarWhenPushed = true
viewController.navigationItem.leftBarButtonItem = UIBarButtonItem.init(imageName: "nav_btn_back_white", higImageName: "", size: .zero, target: self, action: #selector(navBack))
}
super.pushViewController(viewController, animated: animated)
}
//改变状态栏颜色
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
//退出键盘
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
//返回
@objc func navBack() {
self.popViewController(animated: true)
}
}
extension NJF_NavigationViewController {
fileprivate func initializeSet() {
//设置字体大小和颜色
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white,NSAttributedString.Key.font : UIFont.systemFont(ofSize: 18)]
//设置背景色
UINavigationBar.appearance().barTintColor = UIColor.orange
//设置半透明
UINavigationBar.appearance().isTranslucent = false
// 4.设置导航栏背景图片
UINavigationBar.appearance().setBackgroundImage(UIImage(), for: UIBarMetrics.default)
// 5.设置导航栏阴影图片
UINavigationBar.appearance().shadowImage = UIImage()
}
}
- 一些常用常量的定义
/************************application相关*******************/
/// 当前app版本号
let KAppCurrentVersion = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
/// 当前app的build号
let KAppBuildVersion = Bundle.main.infoDictionary!["CFBundleVersion"] as! String
/// 获取设备当前系统
let KSystemVersion = UIDevice.current.systemVersion
/************************屏幕坐标、尺寸相关*******************/
let IS_IPHONE4 = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:640,height:960), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONE5 = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:640,height:1336), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONE6 = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:750,height:1334), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONE6P = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:1242,height:2208), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONE6PBigMode = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:1125,height:2001), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONEX = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:1125,height:2436), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONEXR = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:828,height:1792), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONEXSM = UIScreen.instancesRespond(to:#selector(getter: UIScreen.main.currentMode)) ? __CGSizeEqualToSize(CGSize(width:1242,height:2688), (UIScreen.main.currentMode?.size)!) : false
let IS_IPHONEXAll = (IS_IPHONEX||IS_IPHONEXR||IS_IPHONEXSM)
//适配参数
let suitParm:CGFloat = ((IS_IPHONE6||IS_IPHONEXR||IS_IPHONEXSM) ? 1.12 : (IS_IPHONE6 ? 1.0 : (IS_IPHONE6PBigMode ? 1.01 : (IS_IPHONEX ? 1.0 : 0.85))))
let KscreenWidth = UIScreen.main.bounds.width
let KscreenHeight = UIScreen.main.bounds.height
let kNavigationBarHeight = 44.0
let kStatusBarHeight = IS_IPHONEXAll ? 44.0 : 20.0
let kSafeAreaTopHeight = IS_IPHONEXAll ? 88.0 : 64.0
let kSafeAreaBottomHeight = IS_IPHONEXAll ? 34.0 : 0
let kTabbarHeight = 49.0
- 类拓展
extension UIColor {
convenience init(r: CGFloat, g: CGFloat, b: CGFloat) {
self.init(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1.0)
}
convenience init(rgb: UInt) {
self.init(
red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0,
green: CGFloat((rgb & 0x00FF00) >> 8) / 255.0,
blue: CGFloat(rgb & 0x0000FF) / 255.0,
alpha: CGFloat(1.0)
)
}
class func andomColor() -> UIColor {
return UIColor(r: CGFloat(arc4random_uniform(256)), g: CGFloat(arc4random_uniform(256)), b: CGFloat(arc4random_uniform(256)))
}
}
-
Moya的简单封装
关于网络请求库,用Alamofire
还是Moya
看个人喜好了,个人比较喜欢Moya
lz把Moya的二次封装分了三个类别(实际项目中还应该在封装一层):
1.基础Moya的API部分->MoyaApi
2.url配置类->MoyaApiConfig
3.工具类->MoyaManager
enum MoyaAPI {
/********************登录模块****************/
case register(account:String, password:String)//注册
}
extension MoyaAPI: TargetType {
var baseURL: URL {
return URL.init(string: Moya_BaseUrl)!
}
var path: String {
switch self {
case .register:
return LoginModule_Register
}
}
var method: Moya.Method {
switch self {
case .register:
return .post
// default:
// return .get
}
}
///这个是做单元测试模拟的数据,必须要实现,只在单元测试文件中有作用
var sampleData: Data {
return "".data(using: String.Encoding.utf8)!
}
var task: Task {
switch self {
case let .register(account, password):
return .requestParameters(parameters: ["account":account, "password":password], encoding: JSONEncoding.default)
}
}
var headers: [String : String]? {
// return ["Content-Type":"application/json"]
return nil
}
}
///baseUrl
let Moya_BaseUrl = "https://www.xxx.com"
///path
/***********************登录模块*********************/
let LoginModule_Register = "/login/register"
/// 超时时长
private var requestTimeOut: Double = 15
///成功数据的回调
typealias successCallback = ((Any) -> (Void))
///失败的回调
typealias failedCallback = ((String) -> (Void))
/// endpointClosure用来构建Endpoint
private let myEndpointClosure = { (target: MoyaAPI) -> Endpoint in
let url = target.baseURL.absoluteString + target.path
var endpoint = Endpoint(
url: url,
sampleResponseClosure: { .networkResponse(200, target.sampleData) },
method: target.method,
task: target.task,
httpHeaderFields: target.headers
)
// requestTimeOut = 15 //按照项目需求针对单个API设置不同的超时时长
return endpoint
}
///网络请求的设置
private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
do {
var request = try endpoint.urlRequest()
//设置请求时长
request.timeoutInterval = requestTimeOut
// 打印请求参数
if let requestData = request.httpBody {
print("\(request.url!)"+"\n"+"\(request.httpMethod ?? "")"+"发送参数"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
}else{
print("\(request.url!)"+"\(String(describing: request.httpMethod))")
}
done(.success(request))
} catch {
done(.failure(MoyaError.underlying(error, nil)))
}
}
/// NetworkActivityPlugin插件用来监听网络请求
private let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in
debugPrint("networkPlugin \(changeType)")
//targetType 是当前请求的基本信息
switch(changeType){
case .began:
print("开始请求网络")
case .ended:
print("结束")
}
}
////网络请求发送的核心初始化方法,创建网络请求对象
let Provider = MoyaProvider<MoyaAPI>(endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)
func NetworkRequest(_ target: MoyaAPI, completion: @escaping successCallback, failed:failedCallback?){
Provider.request(target) { (result) in
switch result {
case let .success(response):
do {
//转JSON
let responseObject = try JSONSerialization.jsonObject(with: response.data)
guard let dic = responseObject as? Dictionary<String, Any>, let _ = String(data: response.data, encoding: String.Encoding.utf8) else {
debugPrint("什么情况?不是json数据?????")
return
}
completion(dic)
} catch {
}
case let .failure(error):
failed!(error.localizedDescription)
}
}
}
代码就不一一看了,具体大家可以看看demo,结构还是很好的,后续如果涉及到一些复杂的在更新demo
demo