好多人学习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 要不会死循环
编译不动时候,点击到下面的界面,会有向右的箭头指向一个方法,这个方法数据有问题
- 解析网络数据
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)
}
}