我用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 要不会死循环

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


屏幕快照 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)
}
}

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

推荐阅读更多精彩内容

  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile丽语阅读 3,829评论 0 6
  • 1、范型范型所解决的问题 函数、方法、类型:类,结构体,枚举,元组类型,协议参数,返回值,成员函数参数,成员属性类...
    我是小胡胡123阅读 819评论 0 1
  • 1、随机数 不需要随机数种子 arc4random()%N + begin:产生begin~begin+N的随机数...
    我是小胡胡123阅读 4,146评论 0 2
  • 132.转换错误成可选值 通过转换错误成一个可选值,你可以使用 try? 来处理错误。当执行try?表达式时,如果...
    无沣阅读 1,244评论 0 3
  • 古来贤者,人之敬之。慕其高洁,羡其风骨。素来愚者,人之鄙之。憎其品格,恶其懒惰。我言世人,皆为痴人。 一袭白衣,...
    往生僧阅读 302评论 2 0