swift学习随笔

Swift 的使用随笔

1./**加载xib视图*/
let mainSearchView = Bundle.main.loadNibNamed("MainSearchView", owner: nil, options: nil)?.first as?MainSearchView
mainSearchView?.frame = self.view.bounds
self.view.addSubview(mainSearchView!)

2.使用alamofire做的数据请求
/**alamofire的数据请求*/
Alamofire.request("https://httpbin.org/get").responseJSON { response in
    print(response.request)  // original URL request
    print(response.response) // HTTP URL response
    print(response.data)     // server data
    print(response.result)   // result of response serialization
    
    if let JSON = response.result.value {
        print("JSON: \(JSON)")
    }
}


3.swift 设置image图片
tabbgView.image = UIImage(named: "title_bg.png")

4.swift数据类型的转换
nt转换Float或Double:

let intVar : Int = 3

 let doubleVar : Double = Double(intVar)

Int转换为String:

let intVar : Int = 3

 let strVar : String = String(intVar)

String转换为Int:

let strVar : String = "123"

let intVar : Int? = strVar.toInt()

Double转换为String:

let doubleVar : Double = 3.14

let strVar : String = String(doubleVar)

Double保留两位小数,需要对Double进行扩展:

extension Double {   

 func format(f: String) -> String {       

 return NSString(format: "%\(f)f", self)   

 }

 }

 let myDouble = 1.234567

println(myDouble.format(".2")

String转换Double:

let strVar : String = "3.14"

var string = NSString(string: strVar) string.doubleValue

5.swift使用?的几种情况
    1.声明Optional值变量
    2.用在对Optional值操作中,用来判断是否能响应后面的操作
    3.用于安全调用protocol的optional方法
    4.使用 as? 向下转型(Downcast)

还有一种是在具体的操作前添加!符号,好吧,这又是什么诡异的语法?!
直接上例子,strValue是Optional的String:
let hashValue = strValue!.hashValue
这里的!表示“我确定这里的的strValue一定是非nil的,尽情调用吧” ,比如这种情况:
if strValue {
    let hashValue = strValue!.hashValue
}
{}里的strValue一定是非nil的,所以就能直接加上!,强制拆包(unwrap)并执行后面的操作。 当然如果不加判断,strValue不小心为nil的话,就会出错,crash掉。

6.在新建一个新的工程之后,运行程序可能自动打印好多的log,解决这个问题就在Produc->scheme->Edit Sheme 在Run(debug)找到Environment Verlables 这里添加一个key: OS_ACTIVITY_MODE 并给值disable这样就行了,再次运行就不会出现刚刚那一大堆log了

7.alamofire的数据请求 方式
这里的post、get请求都是不带参数的写法
 Alamofire.request("https://httpbin.org").responseData { response in
            debugPrint("All Response Info: \(response)")
            
            /**获取数据,有中文的话就解码成中文*/
            if let data = response.result.value, let utf8Text = String(data: data, encoding: .utf8) {
                print("Data: \(utf8Text)")
            }
        }

/**alamofire的数据get请求方法 ,post 的请求方式一样的写法*/  
Alamofire.request("https://httpbin.org/get", method: .get).responseData { response in
    debugPrint("All Response Info: \(response)")
    
    /**获取数据,有中文的话就解码成中文*/
    if let data = response.result.value, let utf8Text = String(data: data, encoding: .utf8) {
        print("Data: \(utf8Text)")
    }
}

/**这里的get、post方法传递参数*/
 /**GET Request With URL-Encoded Parameters*/
let parameters: Parameters = ["foo": "bar"]
Alamofire.request("https://httpbin.org/get", parameters: parameters).responseData { (response) in
    /**获取数据,有中文的话就解码成中文*/
    if let data = response.result.value, let utf8Text = String(data: data, encoding: .utf8) {
        print("Data: \(utf8Text)")
    }
}
/**POST Request With URL-Encoded Parameters*/
let parameters2: Parameters = [
    "foo": "bar",
    "baz": ["a", 1],
    /**
      "qux": [
        "x": 1,
        "y": 2,
        "z": 3
    ]
     */
   
]
Alamofire.request("https://httpbin.org/post", parameters: parameters2).responseData{ (response) in
    /**获取数据,有中文的话就解码成中文*/
    if let data = response.result.value, let utf8Text = String(data: data, encoding: .utf8) {
        print("---Data: \(utf8Text)")
    }
}

8.collectionView的初始化,layout设置,cell注册
 /**collectionView的初始化*/
let collectionView:UICollectionView = UICollectionView(frame:self.view.frame,collectionViewLayout:layout)
self.view.addSubview(collectionView)
/**cell注册*/
collectionView.register(UINib(nibName: "CollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "cell")

//定义collectionView的布局类型,流布局
let layout = UICollectionViewFlowLayout()
//设置cell的大小
layout.itemSize = CGSize(width: 40, height: 30)
//滑动方向 默认方向是垂直
layout.scrollDirection = .vertical
//每个Item之间最小的间距
layout.minimumInteritemSpacing = 0
//每行之间最小的间距
layout.minimumLineSpacing = 0

9.Swift和OC的混合编程

 swift 语言出来后,可能新的项目直接使用swift来开发,但可能在过程中会遇到一些情况,某些已用OC写好的类或封装好的模块,不想再在swift 中再写一次,哪就使用混编。这个在IOS8中是允许的。

先中简单的入手,先研究在同一个工程目录下混合使用的情况。

为了演示。先准备两个类

第一个是swift语言写的类,文件名为 act.swift

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片

    import Foundation  
      
    class Act : NSObject  
    {  
        func hasAct(tag:Int) -> String  
        {  
            switch (tag)  
            {  
            case 1:return "Movie"  
            case 2:return "CCTV"  
            case 3:return "Sport TV"  
            default:return "Area TV"  
            }  
        }  
          
        init()  
        {  
            println("act constructor is called.")  
        }  
        deinit  
        {  
            println("act destroyed is called.")  
        }  
    }  
 
第二个是用OC写的类 头文件为OCChannel.h ,实现文件为OCChannel.m

头文件
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片

    #import   
      
    @interface OCChannel : NSObject  
      
    @property (nonatomic,retain) NSString *ChannelName;  
      
    - (NSString *)ChannelChange:(NSInteger) channels;  
      
    @end  


实现文件

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片

    #import "OCChannel.h"  
    #import "SwiftModule-swift.h"  
      
    @interface OCChannel()  
    {  
        Act     *act;  //swift的类  
    }  
    @end  
      
    @implementation OCChannel  
      
    - (id)init  
    {  
        if (self = [super init]) {  
            NSLog(@"OC Constructor is called.");  
            //使用Swift类  
            act = [[Act alloc]init];  
        }  
        return self;  
    }  
      
    - (void)dealloc  
    {  
        NSLog(@"OC Destroyed is called.");  
        //[act release];//ARC not use  
        //[super dealloc];//ARC not use  
    }  
      
    - (NSString *)ChannelChange:(NSInteger) channels  
    {  
        return [act hasAct:channels];  
    }  
      
    @end  


这个OCChannel为中引用了swift 写的类Act 。主要是为了演示在同一个工程项目里,swift类调用OC,同时OC类也调用Swift。从而形成一种混合编写的模式。

下面是具体步骤:

1.新建一个Swift工程:我这里工程名为MixDemo

建好后工程:

2.就是分别引入前面的两个类,咱先一个个来。因为建的是Swift,所以,咱先以Swift工程中引用OC文件进行一次混编

Swift中使用OC

首先Swift中不再使用头文件和.m文件的方式了。所以也不需要使用import ""来导入头文件。哪swift 如何能访问到OC的类声明的。

其实,swift也是需要使用头文件进行访问的,只不过不再需要使用显式的方式使用import进行导入。有两种方式来实现这个头文件的生成。

方式一:在一个全新的Swift,利用第一次新建提示的方式自动添加桥接头文件。

点确定这后就会生成一个以的头文件。

建好后的工程:

这里有一个地方需要注意的就是在targets->build settings ->Object-C Bridging Header 设为哪个桥接的头文件即可。

经过上述步骤,桥接文件弄好了就可以

尽情的把想要在swift类中调用的OC头文件放使用import "" 写到这个桥接文件中吧。就像:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片

    //  
    //  Use this file to import your target's public headers that you would like to expose to Swift.  
    //MixDemo/MixDemo-Bridging-Header.h  
      
    #import "OCChannel.h"  

同样的,当你知道这个swift搜索头文件的关系后,就不需要再理会这个-Bridging-Header.h的文件了。完全可以手工建一个并取自己喜欢的名字。如:

方式二:
新建一个头文件,名为:OCContainerHeader.h
好了,以上的设置后就完全满足了Swift使用OC写的类了。
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片

    import UIKit  
      
    class ViewController: UIViewController {  
                                  
        override func viewDidLoad() {  
            super.viewDidLoad()  
            // Do any additional setup after loading the view, typically from a nib.  
      
            //调用OC类  
            var channel = OCChannel()  
            println(channel.ChannelChange(10))  
            println(channel.ChannelChange(2))  
        }  
      
        override func didReceiveMemoryWarning() {  
            super.didReceiveMemoryWarning()  
            // Dispose of any resources that can be recreated.  
        }  
      
    }  

好了下面再来看一下OC如何调用Swift写的类。(事实上,如果你是一比一抄我这个DEMO,哪么恭喜你,在以上你将编译不通过。因为我的OC类中引用了swfit 写的类,所以你要想运行,就必须把哪个Act 的类注释了才行。)


OC如何调用Swift写的类

OC要想使用,必须有头文件。而swift文件却没有头文件,所在咱们想必也需要产生一个头文件。但对于OC调用swift  的头文件比较特殊。因头文件里面的机制是自动生成的,在不熟悉的,不建议手写。

哪如何产生这个头文件。(注意,系统设置的头文件,在工程中是看不到的。)

产生步骤:

选中targets->build settings ->packing->Product Module Name 中设置模块名,这个名称很重要 swift 的头文件就是根据这个来命名的。

虽然你看图中有这个import "SwiftModule-swift.h"但你在整个工程中是找不到这个文件的,但可以使用CMD+ 鼠标点击可看这个头文件中的内容。

这样,工程中如查Swift要使用OC,则把需要使用的OC类的头文件,全写在MixDemo-Bridging-Header.h里。同样如果OC中所使用的swift类,只需要Clean一把,再编就可以了,但不要忘了导入SwiftModule-swift.h哦(名称自取,但-swift.h是固定的),另外还有一个需要读者注意的。

注:

凡是用Swift写的类,如果不继成自NSObject或NSObject 的派生类,哪么编译后将不会生成对应的转换类。从而使得OC 中找不到相应的声明。

如我的例子中 class Act 这样不会被编译到SwiftModule-swift.h中,但写为 class Act : NSObject,就可以编译出相应的声明。另外可以使用@objc加以声明,但这个还是一样,类最好继承NSObject下来。就像下面:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片

    import Foundation  
      
    @objc(Act)  
      
    class Act   
    {  
        func hasAct(tag:Int) -> String  
        {  
            switch (tag)  
            {  
            case 1:return "Movie"  
            case 2:return "CCTV"  
            case 3:return "Sport TV"  
            default:return "Area TV"  
            }  
        }  
      
        @objc(init)//原本以为加上这个alloc就可以找到,但不行的。。。  
        init()  
        {  
            println("act constructor is called.")  
        }  
          
        deinit  
        {  
            println("act destroyed is called.")  
        }  
    }  

但是在使用时你就会发现

 

        act = [[Act alloc]init]; //报错,找不到alloc,因此建议大家还是继承NSObject.


10.swift 3.0新特性 作者:COSMIN PUPĂZĂ,原文链接,原文日期:2016/06/29
译者:saitjr;校对:Cee;定稿:CMB
本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg。

Apple 在 WWDC 上已将 Swift 3 整合进了 Xcode 8 beta 中,并会在今年晚些时候发布 Swift 3 的正式版。这是 Swift 在开源和支持 Mac OS X 与 Linux 之后的首个版本。如果你在去年 11 月关注了 Swift 进化史 和已经启动的 IBM 沙盒 项目,那你应该知道 Swift 确实改动很多。甚至可以确定你在 Xcode 8 上根本无法编译既有项目。

Swift 3 的改动归结下来主要有两点:

    移除了在 Swift 2.2 就已经弃用的特性
    语言现代化问题

让我们从移除特性讲起,毕竟这点能容易理解,而且在 Xcode 7.3 的时候我们遇到了相关警告。
++ 与 -- 操作符

自增自减是来源于 C 的操作符,作用是对变量直接进行 +1 或 -1 的操作:

var i = 0
i++
++i
i--
--i

然而,在我们要选择使用哪一种操作符进行运算的时候,事情就变得复杂起来。无论是自增还是自减,都对应着两种写法:写在在变量之前,还是在变量之后。它们的底层实现其实都是有返回值的函数,是否使用返回值取决于对运算符的重载。

这可能会吓跑初学者,所以苹果移除了该特性——取而代之的是复合加法运算(+=)与减法运算(-=):

var i = 0
i += 1
i -= 1

当然,你也可以使用普通的加法运算(+)与减法运算(-),虽然复合式运算符写起来要短一点:

i = i + 1
i = i - 1

    延伸阅读:如果你想要了解更多该变更背后的故事,请阅读 Chris Lattner 对移除 ++ 与 -- 的看法。

C 风格的 for 循环已成历史

其实自增自减运算符用得最多的地方,还是在 for 循环部分。移除该运算符意味着 for 循环的特性也随之远去了,因为在 for-in 的世界中,循环控制语句与范围限制用不上该操作符。

如果你有一定编程背景,那么输出 1 到 100 的数,你可能会这样写:

for (i = 1; i <= 10; i++) {
  print(i)
}

在 Swift 3 中,已经不允许这种写法了,而应该写为(注意闭区间范围的写法):

for i in 1...10 {
  print(i)
}

或者,你也可以使用 for-each 加闭包的写法(更多循环相关信息请看这):

(1...10).forEach {
  print($0)
}

    延伸阅读:如果你想要了解更多该变更背后的故事,请阅读 Erica Sadun 对移除 C 风格循环的看法。

移除函数参数的 var 标记

如果不需要在函数内部对参数进行修改的话,函数参数通常都定义为常量。然而,在某些情况下,定义成变量会更加合适。在 Swift 2 中,你可以用 var 关键字来将函数参数标记为变量。一旦参数用 var 来标记,就会生成一份变量的拷贝,如此便能在方法内部对变量进行修改了。

下面是一个求两个数的最大公约数的例子(如果想到回到高中数学课堂再学习一遍,请移步):

func gcd(var a: Int, var b: Int) -> Int {

  if (a == b) {
    return a
  }

  repeat {
    if (a > b) {
      a = a - b
    } else {
      b = b - a
    }
  } while (a != b)

  return a
}

这个算法的逻辑很简单:如果两个数相等,则返回其中一个的值。否则,做大小比较,大的数减去小的数之后,将差值赋值给大的数,然后再将两个数作比较,为止它们相等为止,最终返回其中一个的值。正如你所看到的,通过将 a 和 b 标记为变量,才能在函数体里对两个数进行修改。

Swift 3 不在允许开发者这样来将参数标记为变量了,因为开发者可能会在 var 和 inout 纠结不已。所以最新的 Swift 版本中,就干脆移除了函数参数标记 var 的特性。

如此,想要用 Swift 3 来写上面的 gcd 函数,就要另辟蹊径了。你需要在函数内部创建临时变量来存储参数:

func gcd(a: Int, b: Int) -> Int {

  if (a == b) {
    return a
  }

  var c = a
  var d = b

  repeat {
    if (c > d) {
      c = c - d
    } else {
      d = d - c
    }
  } while (c != d)

  return c
}

    延伸阅读:如果你想要了解更多该变更背后的故事,请阅读决定移除 var 的想法。

函数参数标签的一致性

函数的参数列表底层实现其实是元组,所以只要元组结构和函数参数列表相同,你可以直接用元组来代替参数列表。就拿刚才的 gcd() 函数来说,你可以这样调用:

gcd(8, b: 12)

你也可以这样调用:

let number = (8, b: 12)
gcd(number)

正如你所看到的,在 Swift 2 中,第一个参数无需带标签,而从第二个参数开始,就必须要带标签了。

这个语法对初学者来说可能会造成困惑,所以,要进行统一标签设计。在 Swift 3 中,函数的调用要像下面这样:

gcd(a: 8, b: 12)

即使是第一个参数,也必须带上标签。如果不带,Xcode 8 会直接报错。

你对这修改的第一个反应可能是:「我哔!那我代码改动得多大啊!」是的,这简直是成吨的伤害。所以苹果又给出了一种不用给第一个参数带标签的解决方案。在第一个参数前面加上一个下划线:

func gcd(_ a: Int, b: Int) -> Int {

...

}

但是这样做,事情又仿佛回到了原点——第一个参数不用带标签了。使用这种方式,应该能一定程度上降低 Swift 2 迁移到 Swift 3 上的痛苦。

    延伸阅读:如果你想要了解更多该变更背后的故事,请阅读函数标签一致性的一些想法。

Selector 不再允许使用 String

让我们来创建一个按钮,并给它添加一个点击事件(不需要界面支持,直接使用 playground 就行):

// 1
import UIKit
import XCPlayground

// 2
class Responder: NSObject {

  func tap() {
    print("Button pressed")
  }
}

let responder = Responder()

// 3
let button = UIButton(type: .System)
button.setTitle("Button", forState: .Normal)
button.addTarget(responder, action: "tap", forControlEvents: .TouchUpInside)
button.sizeToFit()
button.center = CGPoint(x: 50, y: 25)

// 4
let frame = CGRect(x: 0, y: 0, width: 100, height: 50)
let view = UIView(frame: frame)
view.addSubview(button)
XCPlaygroundPage.currentPage.liveView = view

让我们一步一步分析下上面的代码:

    导入 UIKit 与 XCPlayground 框架——需要创建一个按钮,并在 playground 的 assistant editor 中进行显示。

    注意:你需要在 Xcode 菜单栏上的 View -> Assistant Editor -> Show Assistant Editor 来开启 assistant editor。

    创建点击的触发事件,能在用户点击按钮时,触发绑定的事件——这需要基类为 NSObject,因为 selector 仅对 Objective-C 的方法有效。

    声明按钮,并配置相关属性。

    声明视图,给定合适的大小,将按钮添加到视图上,最后显示在 playground 的 assistant editor 中。

让我们来看下给按钮添加事件的代码:

button.addTarget(responder, action: "tap", forControlEvents: .TouchUpInside)

这里按钮的 selector 还是写的字符串。如果字符串拼写错了,那程序会在运行时因找不到相关方法而崩溃。

为了解决编译期间的潜在问题,Swift 3 将字符串 selector 的写法改为了 #selecor()。这将允许编译器提前检查方法名的拼写问题,而不用等到运行时。

button.addTarget(responder, action: #selector(Responder.tap), for: .touchUpInside)

    延伸阅读:如果你想要了解更多该变更背后的故事,请阅读 Doug Gregor 的观点。

以上就是关于移除特性的全部内容。接下来,让我们来看看语言现代化的一些亮点。
不再是 String 的 key-path 写法

这个特性和上一个很相似,但是这是用在键值编码(KVC)与键值观察(KVO)上的:

class Person: NSObject {
  var name: String = ""

  init(name: String) {
    self.name = name
  }
}
let me = Person(name: "Cosmin")
me.valueForKeyPath("name")

首先创建了 Person 类,这是 KVC 的首要条件。然后用指定的构造器初始化一个 me,最后通过 KVC 来修改 name。同样,如果 KVC 中的键拼写错误,这一切就白瞎了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值