最近在学swift,本以为多是语法与oc不同,而且都是使用相同的cocoa框架,相同的API,但是或多或少还是有些坑在里,为了避免以后再踩,在这里记下了,以后发现新的坑,也会慢慢在这里加上

[TOC]


1.main文件去哪儿了?

  • OC中main.m中的代码, 通过@UIApplicationMain标记自动生成
  • 可以注掉AppDelegate里的@UIApplicationMain,自己实现Main,不过一般没人这样做
  • 实现下面代码就是OC中的main文件的函数
UIApplicationMain(Process.argc, Process.unsafeArgv, nil, NSStringFromClass(AppDelegate))

2.如何通过字符串创建类对象?

  • 在swift中打印对象时,会发现在类型前面总会有命名空间 .+类名
  • 在swift中用字符串生成类对象就需要拼接成这样的格式,才能成功生成类
  • 注意,命名空间不要加特殊符号,不然依然无法获取控制器类
//获取命名空间,在info.plist文件里就是Executable file
let nameSpace = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
//拼接成固定格式
let controller:AnyClass = NSClassFromString(nameSpace + "." + controllerName)!
//创建对象
let viewController = (controller as! UIViewController.Type).init()

3.Swift中的Any,AnyObject,AnyClass分别代表是什么?

  • AnyObject: 相当于OC中的id, 表示所有class类型的数据, 所有继承与NSObject的类都隐式实现了protocol AnyObject协议, 所以他可以表示所有的class类型
  • Any:所有基本数据类型和enum/ struct都可以用Any来表示

    注意: 有的时候你会发现将基本数据类型或者enum/ struct通过AnyObject来保存也不会报错, 这是因为Swift中很多数据类型可以和OC中的数据类型进行自动转换, 系统内部已经将他们转换为了OC的对象类型

  • AnyClass: 用来表示任意类的类类型(元类型)

      typealias AnyClass = AnyObject.Type
    .Type用于获取类的元类型, 例如Person.Type就代表着获取Person的元类型
    .self如果通过类名调用, 那么可以获取该类的类型, 说白了就是获取自己

4.在Swife中如何抓取异常?

  • 在Swift中抓取异常需要do,catch,try这三个关键字
  • 这里举个json序列化的例子
do{
let path = /..路径../
let data =/..转data../
//编译器会要求你实行异常检测,于是在序列化前面添加try字段
//外部包裹do,catch,显而易见出错自然会走catch
let dicArr = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) }catch
{
// 如果抛出异常就会来到catch }

5.在swift中如何定义全局打印方法

  • 由于swift没有宏,我们不能像oc那样去定义
  • 直接在AppDelegate中写,反正哪里都可以用
  • 用泛型传参
  • 如何判断调试与发布状态呢?
  • 在Build settings里找到Swift Compiler-custom Flags
  • 在other swift flags 的Debug里添加两个字段
  • "-D"
  • "DEBUG"
  • 代码中直接判断就行
func HJSLog<T>(message: T)
{
#if DEBUG
print("\(message)") #endif
}

6.在swift中,单例怎么写?

  • 在swift中,单例有两种写法
  • 一种是按照OC的思维去写
     static var onceToken: dispatch_once_t = 0
static var instance: NetworkTools? class func shareNetworkTools() -> NetworkTools
{ dispatch_once(&onceToken) { () -> Void in
print("我被调用了")
instance = NetworkTools()
} return instance!
}
  • 另一种就是swift的纯正写法
  • 在swift中,let本身就只会创建一次,可以运用这个特性
  • let是线程安全的
static let instance: NetworkTools = NetworkTools()
class func shareNetworkTools() -> NetworkTools
{
return instance
}

7.在swift中如何私有化点击事件方法

  • 一般我们不公开方法会在前面添加private
  • 但是例如按钮点击方法,光是添加private是不够的
  • 因为swift的方法调用是在编译时就决定了
  • 而点击事件方法由于是来自于runloop中
  • 编译器不会它一起编译进来,只有在运行时呼叫,这属于OC的调用方式
  • 所以我们还需要再在方法前面加上@objc
//按钮点击handle
@objc private func composeClick(){ }`

8.在swift中如何懒加载

  • 在swift中对懒加载有专门的关键字
///懒加载一个imageView
private lazy var icon:UIImageView = {
let imageV = UIImageView(image: UIImage(named: "visitordiscover_feed_image_smallicon"))
return imageV
}()

9.在swift中的协议(protocol)

  • 在swift中定义协议也很简单
  • 只需要在类前定义就行
    @objc
    protocol VisitorViewDelegate:NSObjectProtocol
    {
    //点击注册按钮
    optional func visitorViewDidRegisterBtnClick(visitView: VisitorView)
    //点击登录按钮
    optional func visitorViewDidLoginBtnClick(visitView:VisitorView)
    }
  • 代理属性需要设定为weak,防止循环引用
    weak var delegate:VisitorViewDelegate?
  • 在调用代理方法时,代理作为可选属性,已经帮我们预防代理不存在的可能
  • 我们还需要借助可选属性来预防方法未实现
  • 当然在确定实现的前提下可以解包
    ///注册handle
    @objc private func registerClick(){
    delegate?.visitorViewDidRegisterBtnClick!(self)
    }
    ///登录handle
    @objc private func loginClick(){ delegate?.visitorViewDidLoginBtnClick?(self)
    }

10.在swift中如何写分类

  • 我刚从oc转过来就遇到了如何在swift中写分类的问题
  • swift中写分类很简单
  • extension就是swift中的分类
  • 例如给UIBarbuttonItem添加分类
  • 新建一个UIBarButtonItem+Extension.swift文件
import UIKit

extension UIBarButtonItem
{
convenience init(target:AnyObject?,action:Selector,image:String) { let btn = UIButton(type: UIButtonType.Custom)
btn.setImage(UIImage(named: image), forState: UIControlState.Normal)
btn.setImage(UIImage(named: image + "_highlighted"), forState: UIControlState.Highlighted) btn.addTarget(target, action: action, forControlEvents: UIControlEvents.TouchUpInside) self.init(customView:btn)
}
}

11.为何经常被强制实现init(coder: NSCoder)

  • 因为Objective-C 和 Swift 中都没有直接的这样的抽象函数语法支持
  • 然而有些时候我们却有不想让别人调用某个方法,但又不得不将其暴露出来的时候。
  • 一般满足这种需求的就是抽象类型或者抽象函数
  • 在面对这种情况时,为了确保子类实现这些方法,而父类中的方法不被错误地调用,我们就可以利用 fatalError 来在父类中强制抛出错误,以保证使用这些代码的开发者留意到他们必须在自己的子类中实现相关方法:
class MyClass {
func methodMustBeImplementedInSubclass() {
fatalError("这个方法必须在子类中被重写")
}
} class YourClass: MyClass {
override func methodMustBeImplementedInSubclass() {
print("YourClass 实现了该方法")
}
} class TheirClass: MyClass {
func someOtherMethod() { }
} YourClass().methodMustBeImplementedInSubclass()
// YourClass 实现了该方法 TheirClass().methodMustBeImplementedInSubclass()
// 这个方法必须在子类中被重写
  • 不仅仅是对于类似抽象函数的使用中可以选择 fatalError,对于其他一切我们不希望别人随意调用,但是又不得不去实现的方法,我们都应该使用 fatalError 来避免任何可能的误会。比如父类标明了某个 init 方法是 required 的,但是你的子类永远不会使用这个方法来初始化时,就可以采用类似的方式, 被广泛使用 (以及被广泛讨厌的) init(coder: NSCoder) 就是一个例子。在子类中,我们往往会写
required init(coder: NSCoder) {
fatalError("NSCoding not supported")
}

12.在swift中使用guard与fatalError配合抛出异常

  • 在严谨的开发中会经常用到断言
  • 前面一条介绍了fatalError来抛出错误
  • 这条就来介绍一下guardfatalError的配合使用达到断言的效果
    guard let safeValue = criticalValue else {
    fatalError("criticalValue cannot be nil here")
    }
    someNecessaryOperation(safeValue)
  • 本来我认为if也可以达到这样的效果
    if let safeValue = criticalValue {
    someNecessaryOperation(safeValue)
    } else {
    fatalError("criticalValue cannot be nil here")
    }
  • 或者
    if criticalValue == nil {
    fatalError("criticalValue cannot be nil here")
    }
    someNecessaryOperation(criticalValue!)
  • 但是看到有些博客这么说:

    这个flatten code以其他方式进入一个if let 代码块,并且在靠近相关的环境中过早地退出了,而不是进入else代码块。甚 至当你没有捕获一个值(guard let),这个模式在编译期间也会强制过早退出。在第二个if的例子里,尽管代码flattend得像guard一样,但是一个毁灭性的错误或者其他返回 一些无法退出的进程(或者基于确切实例的非法态)将会导致crash。一个过早的退出发生时,guard声明将会及时发现错误,并将其从else block中移除。(这博主翻译得真烂)

  • 所以,还是用guard比较好

    13.在swift中,互斥锁变成什么样了?

  • 在swift中,互斥锁如何写
  • oc中的互斥锁:
@synchronized(self) {
//需要执行的代码块
}
  • swift中的互斥锁
objc_sync_enter(self)
//需要执行的代码块
objc_sync_exit(self)
  • 至于其他多线程的API和以前的一样,只是少了perform这一类的API,苹果已经去掉了

14.在swift中,引用self时,如何避免循环引用

  • 在oc中,我们需要在代码块用到self时,可以直接把self付给其他变量,然后在块中使用完毕后制空,或者像下面弱引用self来避免循环引用:

    __weak typeof(self) weakSelf = self;
  • 那么在swift中我们怎么办到这点呢?
  • 很简单,看下面代码
    //这里用gcd举例不好,毕竟系统的块不会造成循环引用,这里就勉强的学一下怎么改吧
    dispatch_async(dispatch_get_global_queue(0, 0)) {[unowned self] () -> Void in
    self.view
    //添加自己的代码
    }
  • 只需要在闭包里加入[unowned self]即可
文/哟_Json(简书作者)
原文链接:http://www.jianshu.com/p/b5c87824e33c
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

那些年,学swift踩过的坑的更多相关文章

  1. 项目中踩过的坑之-sessionStorage

    总想写点什么,却不知道从何写起,那就从项目中踩过的坑开始吧,希望能给可能碰到相同问题的小伙伴一点帮助. 项目情景: 有一个id,要求通过当前网页打开一个新页面(不是当前页面),并把id传给打开的新页面 ...

  2. 《C++之那些年踩过的坑(二)》

    C++之那些年踩过的坑(二) 作者:刘俊延(Alinshans) 本系列文章针对我在写C++代码的过程中,尤其是做自己的项目时,踩过的各种坑.以此作为给自己的警惕. 今天讲一个小点,虽然小,但如果没有 ...

  3. 初学spring boot踩过的坑

    一.搭建spring boot环境 maven工程 pom文件内容 <project xmlns="http://maven.apache.org/POM/4.0.0" xm ...

  4. python抓取360百科踩过的坑!

    学习python一周,学着写了一个爬虫,用来抓取360百科的词条,在这个过程中.因为一个小小的修改,程序出现一些问题,又花了几天时间研究,问了各路高手,都没解决,终于还是自己攻克了,事实上就是对lis ...

  5. web开发实战--弹出式富文本编辑器的实现思路和踩过的坑

    前言: 和弟弟合作, 一起整了个智慧屋的小web站点, 里面包含了很多经典的智力和推理题. 其实该站点从技术层面来分析的话, 也算一个信息发布站点. 因此在该网站的后台运营中, 富文本的编辑器显得尤为 ...

  6. 从0开始学Swift笔记整理(五)

    这是跟在上一篇博文后续内容: --Core Foundation框架 Core Foundation框架是苹果公司提供一套概念来源于Foundation框架,编程接口面向C语言风格的API.虽然在Sw ...

  7. 从0开始学Swift笔记整理(四)

    这是跟在上一篇博文后续内容: --重写方法 重写实例方法 在子类中重写从父类继承来的实例方法和静态方法.先介绍实例方法的重写. 下面看一个示例: class Person {        var n ...

  8. 从0开始学Swift笔记整理(三)

    这是跟在上一篇博文后续内容: --Swift中相关的属性 存储属性 Swift中的属性分为存储属性和计算属性,存储属性就是Objective-C中的数据成员,计算属性不存储数据,但可以通过计算其他属性 ...

  9. 从0开始学Swift笔记整理(二)

    这是跟在上一篇博文后续内容: --函数中参数的传递引用 类是引用类型,其他的数据类型如整型.浮点型.布尔型.字符.字符串.元组.集合.枚举和结构体全部是值类型. 有的时候就是要将一个值类型参数以引用方 ...

随机推荐

  1. CSS 布局Float 【0】

    float是 css 样式的定位属性.我们在印刷排版中,文本可以按照需要围绕图片.一般把这种方式称为“文本环绕”.在网页设计中,应用了CSS的float属性的页面元素就像在印刷布局里面的被文字包围的图 ...

  2. Hive学习之七《 Sqoop import 从关系数据库抽取到HDFS》

    一.什么是sqoop Sqoop是一款开源的工具,主要用于在Hadoop(Hive)与传统的数据库(mysql.postgresql...)间进行数据的传递,可以将一个关系型数据库(例如 :MySQL ...

  3. Hive学习之三 《Hive的表的详解和应用案例详解》

    一.Hive的表 Hive的表分为内部表.外部表和分区表. 1.内部表,为托管表. 2.外部表,external. 3.分区表. 详解: 内部表,删除表的时候,数据会跟着删除. 外部表,在删除表的时候 ...

  4. WebForm,Winfrom下拉框添加全部行

    WebForm: dropPostalLineNo.DataSource = "数据源";        dropPostalLineNo.DataTextField = &quo ...

  5. JS判断鼠标从哪个方向进入DIV容器

    写的不够高大上 , 不要介意哦... Js: //进去 $(".flash").bind("mouseenter",function(e){ /** the w ...

  6. css position 相对定位

    <html> <head> <style type="text/css"> h2.pos_left { position:relative; l ...

  7. Python自动化运维之16、线程、进程、协程、queue队列

    一.线程 1.什么是线程 线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位. 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行 ...

  8. 嵌入式学习笔记(虚拟机共享文件夹配置-Ubuntu系统中)

    最近在学习Linux的操作系统,使用的是虚拟机.由于一些文件需要在主机和虚拟机中都要编辑,如果可以使得文件共享,可以极大的提高工作效率! 配置共享文件的步骤如下: [第一步] 在虚拟机软件中设置 [第 ...

  9. listen函数

    listen函数仅仅由TCP服务器调用,它做2件事: 1)当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect发起连接的客户套接字 listen函数把一 ...

  10. 11 - 改变vtkImageData中的Manipulation 方法 VTK 6.0 迁移

    VTK6 引入了许多不兼容的变.这其中就包括关于vtkImageData中元数据管理及内存分配的方法.这些方法有些直接改变了行为或者能加了额外的参数. GetScalarTypeMin() GetSc ...