一个简单的swift项目

简述:swift语法看的差不多后,就写了个简单的项目架构(其中涉及的语法还是很多的),一写起来,就感觉swift赏心悦目有木,虽说有些地方很晦涩,但是熟悉起来就好了,建议学swift还是先研究语法,这样上手会轻松很多,下面上代码

关于代码里面涉及的语法就不啰嗦了,大家根据自己所学对照验证

  • UITabBarController

LZ用的是读取info.plist方式获取tabBarItem配置信息

屏幕快照 2019-04-18 下午4.15.29.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271