我用Swift开发项目踩过的坑

好多人学习swift,语法什么的很快就学会了,但是要做项目的话,有不少细节及注意点.最近我用swift开发项目,踩过的坑一一列出.

宏定义

oc上的宏定义没有了,swift中用let或者函数代替,swift随便建立一个swift文件都可以当成oc的pch文件使用,在里面写常量.

func kfont(f: CGFloat) -> UIFont {return UIFont.systemFont(ofSize: f)}
let kScreenWidth = UIScreen.main.bounds.size.width

  • 强转成字典和数组

    let dic = data as! [String:AnyObject]
    let statues = dic["statuses"] as! [AnyObject]
    option+ command +/ 代码注释
    option + 点击变量 显示变量类型
    删除数组中指定元素要用 NSMutableArray
    var selectedBtnArray : NSMutableArray = []//选中的按钮

  • //字典转json
    

    static func toJSONString(dict: [String: Any])-> String {
    let data = try? JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions.prettyPrinted)
    let strJson = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
    return strJson! as String
    }
    json格式字符串转字典:
    guard let dic = response as? [String: Any] else { return }
    //string转字典
    func getDictionaryFromJSONString(jsonString: String) ->NSDictionary{
    let jsonData:Data = jsonString.data(using: .utf8)!
    let dict = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
    if dict != nil {
    return dict as! NSDictionary }
    return NSDictionary()
    }

  • string —> data data — string

let testData = str.data(using: String.Encoding.utf8.rawValue)
let data = json.data(using: String.Encoding(rawValue: String.Encoding.utf8.rawValue))!

    var backToString = String(data: imageData, encoding: String.Encoding.utf8) as String!
  • string去掉空格和换行
    let str = backToString?.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)
  • tableView的数据源代理方法可以写在类下面的extension里面

extension ZJDetectController{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}

  • kvo
    1,在写swift的KVO的过程中,其不能监听基本数据类型的属性,若想监听需将其改成NSNumber类型,或其它类型,否则监听的代理方法不走。
    2,在写swift的KVO的过程中,被监听的属性必须用“dynamic”修饰,否则监听的代理方法不走。
    //kvo的属性要这样做 dynamic NSNumber
    dynamic var totalH : NSNumber = 155 //一行 self?.totalH = NSNumber(value: Float(btn.maxY + 35))

addView.addObserver(self, forKeyPath: "totalH", options: .new, context: nil)
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let change = change else { return }
let totalH : CGFloat = change[NSKeyValueChangeKey.newKey] as! CGFloat
print("totalH",totalH)
currentAddView?.height = totalH
}
deinit {
self.removeObserver(self, forKeyPath: "totalH")

  • set get

var zimu : String?{
didSet{
titleLabel?.text = zimu
}
}
// var zimu2: String?{
// guard let kzimu = zimu else {
// return nil
// }
//
// return "22(kzimu)"
// }

  • 键盘和文本框精确对齐

注册键盘willShow的通知
override func keyboardWillShow(notification: Notification){
let dict: [String: AnyObject] = notification.userInfo as! [String : AnyObject]
let aValue : CGRect = (dict as NSDictionary).object(forKey: UIKeyboardFrameEndUserInfoKey) as! CGRect
let keyboardH = aValue.size.height
var delta: CGFloat = 0.0
if keyboardH <= CGFloat(0) {
return
}
let window = UIApplication.shared.keyWindow!
history_Y_offset = (currentTextView?.convert((currentTextView?.bounds)!, to: window).origin.y)!
delta = self.history_Y_offset - (kScreenHeight - keyboardH - 90);
var offset = self.backScrollVi.contentOffset;
offset.y += delta;
if ((offset.y) < CGFloat(0) ) {
offset.y = 0;
}
if (self.history_Y_offset + 80 + keyboardH > kScreenHeight) {
self.backScrollVi.setContentOffset(offset, animated: true)
}
}

  • 用闭包自定义一个可以点击的label,label文字可以有偏移量

var inset : UIEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0)
var labelTapClosure: (( _ label: ZJLabel)->())?
override init(frame: CGRect) {
super.init(frame: frame)
self.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(zjLabelTap(recognizer:)))
self.addGestureRecognizer(tap)
}
@objc func zjLabelTap(recognizer: UITapGestureRecognizer){
let label = recognizer.view as! ZJLabel
if labelTapClosure != nil {
labelTapClosure?(label)
}
}
convenience init(insets: UIEdgeInsets) {
self.init()
inset = insets
}
override func drawText(in rect: CGRect) {
return super.drawText(in: UIEdgeInsetsInsetRect(rect, inset))
}

  • 异步

DispatchQueue.global().async {
print("开始执行异步任务")
Thread.sleep(forTimeInterval: 2)
print("异步任务执行完毕")
DispatchQueue.main.async {
print("回到UI线程")
}
}

  • 颜色16进制转换

extension UIColor {
//类方法 static func
static func colorWithHex(hexColor:Int64)->UIColor{
let red = ((CGFloat)((hexColor & 0xFF0000) >> 16))/255.0;
let green = ((CGFloat)((hexColor & 0xFF00) >> 8))/255.0;
let blue = ((CGFloat)(hexColor & 0xFF))/255.0;
return UIColor(red: red, green: green, blue: blue, alpha: 1)
}
}

  • 代理

    // 定义代理协议
    protocol ZJLoginViewDelegate: NSObjectProtocol {
    func didClickLoginBtn(account: String,passWord: String)
    }
    // 定义代理对象
    weak var loginDelegate: ZJLoginViewDelegate?
    if loginDelegate != nil {
    loginDelegate?.didClickLoginBtn(account: kaccount , passWord: kpassWord )
    }

  • 闭包之间传递

typealias DateClosure = (( _ dateStr: String)->())?
var callBackClosure : DateClosure?
convenience init(date: (( _ dateStr: String)->())? ) { self.init()
callBackClosure = date
}
@objc private func btnClick(){
if callBackClosure != nil {
callBackClosure!!(dateStr ?? "")
}
}

  • 闭包传值
    传出类

    var loginButtonClosure: (( _ account: String, _ pass: String)->())?
    if loginButtonClosure != nil {
    loginButtonClosure?(kaccount, kpassWord )

    }
    传入类
    loginVi.loginButtonClosure = {(account, pass) in
    }
  • 直接从字典取值判断字典value 为空
        guard let dic = response as? [String: Any] else { return }
        guard let resultDict = dic["result"] as? [String: Any] else {   return}
        //添加
        for  e in resultDict {
            if (e.value as AnyObject).isEqual(NSNull.init()) {//value为null
            }else{
               let str = String(describing: e.value)
                print("非空",e.value,str)
                self.dictSave[e.key] = String(describing:resultDict[e.key])
            }
  • bug
    自定义textField时候 设置leftViewframe时候不能在layoutSubView里面时用self.width和 self.leftViewMode = .always 要不会死循环

编译不动时候,点击到下面的界面,会有向右的箭头指向一个方法,这个方法数据有问题


我用Swift开发项目踩过的坑_第1张图片
屏幕快照 2017-03-15 15.42.12.png
  • 解析网络数据

guard let dic = response as? [String: Any] else { return }
guard let statusArray = dic["result"] as? [[String: Any]] else { return}
let statusArr = NSArray.yy_modelArray(with: ChectDetectM.self, json: statusArray) as! [ChectDetectM] //转成模型数组
// 普通转模型
let loginM1 = ZJLoginM.yy_model(withJSON: json)

封装AFN

import UIKit
import AFNetworking
enum RequestType: Int {
case GET
case POST
}
class JDNetworkTools: AFHTTPSessionManager {
// 闭包回调类型的别名
typealias CallBackType = (Any?,Error?)->()
// 单例全局访问点
static let sharedTools: JDNetworkTools = {
let tools = JDNetworkTools(baseURL: NSURL(string: kBaseURL)! as URL)
tools.responseSerializer.acceptableContentTypes?.insert("text/html")
tools.responseSerializer.acceptableContentTypes?.insert("text/plain")
tools.requestSerializer.timeoutInterval = 20
return tools
}()
//@escaping 逃逸闭包 在当函数参数传入异步返回执行时候加上
fileprivate func request(type: RequestType,url: String,params: Any?,callback: @escaping CallBackType){
//utr8
let urlS = url.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)
guard let urlStr = urlS else { return }
if type == RequestType.GET {
get(urlStr, parameters: params, progress: nil, success: { (, response) in
callback(response,nil)
}, failure: { (
, error) in
callback(nil,error)
})
}else if type == RequestType.POST {
post(urlStr, parameters: params, progress: nil, success: { (, response) in
callback(response, nil)
}, failure: { (
, error) in
callback(nil, error)
})
}
}
}
extension JDNetworkTools{
// MARK: 登陆
func login(aesStr: NSString,callback: @escaping CallBackType) {
let url = "auth/login.do"
let params: [String: Any] = [
"token": aesStr,
]
request(type: .GET, url: url, params: params, callback: callback)
}
}

你可能感兴趣的:(我用Swift开发项目踩过的坑)