2016年2月

GCD的基本使用以及常用的方法

//
//  ViewController.swift
//  GCD
//
//  Created by admin on 16/2/22.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    /**
     概念
     任务:闭包
     队列:存放任务,先进先出的原则
     串行队列:任务一个一个顺序执行
     并发队列:同时取出多个任务

     同步sync:不会开辟新线程
     异步async:会开新线程

     串行队列同步执行:不开线程,在原来的线程里面顺序执行
     串行队列异步执行:开一条线程,在新线程里面顺序执行
     并发队列同步执行:不开线程,在原来线程顺序执行
     并发队列异步执行:开多条线程,在开辟的新线程里面执行

     总结
     1.是否sync决定是否开辟新任务
     2.开多少线程由队列决定,串行最多开一个,并发可以开多个,有GCD底层决定
     */
    @IBOutlet weak var imageView: UIImageView!
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.gcdL()
    }
    // 定义once变量
    static var once = dispatch_once_t()
    func gcdL()
    {
        print(ViewController.once)// 第一次打印 0
        dispatch_once(&ViewController.once) { () -> Void in
            print("只执行一次")
        }
        print(ViewController.once)// 打印 -1
        print("ok")
    }
    // 组队列
    func gcdK()
    {
        let queueGroup = dispatch_group_create()
        let queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT)
        dispatch_group_async(queueGroup, queue) { () -> Void in
            print(NSThread.currentThread())
            print("下载a")
        }
        dispatch_group_async(queueGroup, queue) { () -> Void in
            print(NSThread.currentThread())
            print("下载b")
        }
        dispatch_group_async(queueGroup, queue) { () -> Void in
            print(NSThread.currentThread())
            print("下载c")
        }
        // 队列里面的所有任务执行完毕之后执行,可以跨队列通信
        dispatch_group_notify(queueGroup, dispatch_get_main_queue()) { () -> Void in
            print(NSThread.currentThread())
            print("下载完毕")
        }
    }
    // 延迟执行
    func gcdJ()
    {
        let time = dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC))
        /**
       第一个参数:表示从现在开始经过多少纳秒之后
       第二个参数:在哪个队列中执行
        */
        dispatch_after(time, dispatch_get_main_queue()) { () -> Void in
            print(NSThread.currentThread())
        }
    }
    // GCD线程间通信
    func gcdI()
    {
        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
            let data = NSData(contentsOfURL: NSURL(string: "http://e.hiphotos.baidu.com/image/pic/item/29381f30e924b8995d7368d66a061d950b7bf695.jpg")!)
            let image = UIImage(data: data!)
            print(NSThread.currentThread())
            dispatch_sync(dispatch_get_main_queue(), { () -> Void in
                print(NSThread.currentThread())
                self.imageView.image = image
            })
        }
    }
    func gcdH()
    {
        let queue = dispatch_get_global_queue(0, 0)
        for var i = 0;i < 10;i++
        {
            print("主队列")
            dispatch_async(queue) { () -> Void in
                print(NSThread.currentThread())
            }
        }
    }
    /**
     全局队列跟并发队列的区别
     1. 全局队列没有名称 并发队列有名称
     2. 全局队列,是供所有的应用程序共享。
     3. 在MRC开发,并发队列,创建完了,需要释放。 全局队列不需要我们管理
     */
    func gcdG()
    {
        /**
         参数:第一个参数,一般 写 0(可以适配 iOS 7 & 8)
         iOS 7
         DISPATCH_QUEUE_PRIORITY_HIGH 2  高优先级
         DISPATCH_QUEUE_PRIORITY_DEFAULT 0  默认优先级
         DISPATCH_QUEUE_PRIORITY_LOW (-2) 低优先级
         DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后台优先级

         iOS 8
         QOS_CLASS_DEFAULT  0

         第二个参数:保留参数 0
         */
        let queue = dispatch_get_global_queue(0, 0)
        for var i = 0;i < 10;i++
        {
            print("主队列")
            dispatch_sync(queue) { () -> Void in
                print(NSThread.currentThread())
            }
        }
    }
    // 主队列异步
    func gcdF()
    {
        let queue = dispatch_get_main_queue()
        for var i = 0;i < 10;i++
        {
            print("主队列")
            dispatch_async(queue) { () -> Void in
                print(NSThread.currentThread())
            }
        }
    }
    /**
     主队列:专门负责在主线程上调度任务,不会在子线程调度任务,在主队列不允许开新线程.
     同步执行:要马上执行
     结果:死锁
     */
    func gcdE()
    {
        // 1. 获得主队列-> 程序启动,--> 至少有一个主线程-> 一开始就会创建主队列
        let queue = dispatch_get_main_queue()
        for var i = 0;i < 10;i++
        {
            print("主队列")
            // 同步:把任务放到主队列里,但需是马上执行
            dispatch_sync(queue) { () -> Void in
                print(NSThread.currentThread())
            }
        }
    }
    /**
     并发队列:可以同时执行多个任务
     异步执行:肯定会开新线程,在新线程执行
     结果:会开很多个线程,同时执行
     */
    func gcdD()
    {
        let queue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT)
        for var i = 0;i < 10;i++
        {
            dispatch_async(queue) { () -> Void in
                print(NSThread.currentThread())
            }
        }
    }
    /**
     并发队列:可以同时执行多个任务
     同步任务:不会开辟新线程,是在当前线程执行
     结果:不开新线程,顺序一个一个执行。
     */
    func gcdC()
    {
        let queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT)
        for var i = 0;i < 10;i++
        {
            dispatch_sync(queue) { () -> Void in
                print(NSThread.currentThread())
            }
        }
    }
    /**
     串行队列:一个一个执行
     异步执行:肯定会开新线程,在新线程执行
     结果:只会开一个线程,而且所有任务都在这个新的线程里面执行
     */
    func gcdB()
    {
        let queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL)
        for var i = 0;i < 10;i++
        {
            dispatch_async(queue) { () -> Void in
                print(NSThread.currentThread())
            }
        }
    }
    /**
     串行队列:顺序,一个一个执行
     同步任务:不会开辟新线程,是在当前线程执行
     结果:不开新线程,在当前线程顺序执行

     dispatch : 调度,GCD里面函数,都是以dispatch开头的
     */
    func gcdA()
    {
        let queue = dispatch_queue_create("queue", nil)
        dispatch_sync(queue) { () -> Void in
            print(NSThread.currentThread())
        }
    }
}

swift线程间通讯

//
//  ViewController.swift
//  多线程
//
//  Created by admin on 16/2/17.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    var ticketsNumber = 20
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        self.performSelectorInBackground("getImage", withObject: nil)
    }
    func getImage()
    {
        // oc子线程里面的runloop默认不开启, 也就意味不会自动创建自动释放池, 子线程里面autorelease的对象 就会没有池子可放。 也就意味后面没办法进行释放。 造成内存泄露
        // 所以需要手动创建,好像不是的
        print(NSThread.currentThread())
        let data = NSData(contentsOfURL: NSURL(string: "http://f.hiphotos.baidu.com/image/pic/item/7aec54e736d12f2eec17b2b54bc2d562843568d0.jpg")!)
        // 更新ui要在主线程,所以这里把获取到的图片去主线程赋值
        //self.performSelectorOnMainThread(Selector("assignImage:"), withObject: UIImage(data: data!), waitUntilDone: false)
//        self.performSelector(Selector("assignImage:"), onThread: NSThread.mainThread(), withObject: UIImage(data: data!), waitUntilDone: false, modes: [NSRunLoopCommonModes])
        self.performSelector(Selector("assignImage:"), onThread: NSThread.mainThread(), withObject: UIImage(data: data!), waitUntilDone: false)

    }
    class Jin {
        deinit
        {
            print("对象销毁啦。。。")
        }
    }
    func assignImage(image:UIImage)
    {
        print(NSThread.currentThread())
        self.imageView.image = image
    }
}

swift自动释放池,性能优化

Swift在内存管理上使用的是自动引用计数(ARC)的一套方法,在ARC中虽然不需要手动地调用像是retain,release或者是autorelease这样的方法来管理引用计数,但是这些方法还是都会被调用的——只不过是编译器在编译时在合适的地方帮我们加入了而已。其中retain和release都很直接,就是将对象的引用计数加一或者减一。但是autorelease就比较特殊一些,它会将接受该消息的对象放到一个预先建立的自动释放池 (auto release pool)中,并在自动释放池收到drain消息时将这些对象的引用计数减一,然后将它们从池子中移除(这一过程形象地称为“抽干池子”)。
在App中,整个主线程其实是跑在一个自动释放池里的,并且在每个主Runloop结束时进行drain操作。这是一种必要的延迟释放的方式,因为我们有时候需要确保在方法内部初始化的生成的对象在被返回后别人还能使用,而不是立即被释放掉。
在Objective-C中,建立一个自动释放池的语法很简单,使用@autoreleasepool就行了。如果你新建一个Objective-C项目,可以看到main.m中就有我们刚才说到的整个项目的autoreleasepool:

int main(int argc, char *argv[]) {  
    @autoreleasepool {  
        int retVal = UIApplicationMain(  
            argc,   
            argv,   
            nil,   
            NSStringFromClass([AppDelegate class]));  
        return retVal;  
    }  
}  

更进一步,其实@autoreleasepool在编译时会被展开为NSAutoreleasePool,并附带drain方法的调用。

而在Swift项目中,因为有了@UIApplicationMain,我们不再需要main文件和main函数,所以原来的整个程序的自动释放池就不存在了。即使我们使用main.swift来作为程序的入口时,也是不需要自己再添加自动释放池的。

但是在一种情况下我们还是希望自动释放,那就是在面对在一个方法作用域中要生成大量的autorelease对象的时候。在Swift 1.0时,我们可以写这样的代码:

func loadBigData() {  
    if let path = NSBundle.mainBundle()  
        .pathForResource("big", ofType: "jpg") {  
        for i in 1...10000 {  
            let data = NSData.dataWithContentsOfFile(  
                path, options: nil, error: nil)  
            NSThread.sleepForTimeInterval(0.5)  
        }          
    }  
}  

dataWithContentsOfFile返回的是autorelease的对象,因为我们一直处在循环中,因此它们将一直没有机会被释放。如果数量太多而且数据太大的时候,很容易因为内存不足而崩溃。在Instruments下可以看到内存alloc的情况:
这显然是一幅很不妙的情景。在面对这种情况的时候,正确的处理方法是在其中加入一个自动释放池,这样我们就可以在循环进行到某个特定的时候施放内存,保证不会因为内存不足而导致应用崩溃。在Swift中我们也是能使用autoreleasepool的——虽然语法上略有不同。相比于原来在Objective-C中的关键字,现在它变成了一个接受闭包的方法:

func autoreleasepool(code: () -> ())  

利用尾随闭包的写法,很容易就能在Swift中加入一个类似的自动释放池了:

func loadBigData() {  
    if let path = NSBundle.mainBundle()  
        .pathForResource("big", ofType: "jpg") {  
        for i in 1...10000 {  
            autoreleasepool {  
                let data = NSData.dataWithContentsOfFile(  
                    path, options: nil, error: nil)  
                NSThread.sleepForTimeInterval(0.5)  
            }  
        }          
    }  
}   

这样改动以后,内存分配就没有什么忧虑了:
这里我们每一次循环都生成了一个自动释放池,虽然可以保证内存使用达到最小,但是释放过于频繁也会带来潜在的性能忧虑。一个折中的方法是将循环分隔开加入自动释放池,比如每10次循环对应一次自动释放,这样能减少带来的性能损失。

其实对于这个特定的例子,我们并不一定需要加入自动释放。在Swift中更提倡的是用初始化方法而不是用像上面那样的类方法来生成对象,而且在Swift 1.1中,因为加入了可以返回nil的初始化方法,像上面例子中那样的工厂方法都已经从API中删除了。今后我们都应该这样写:

let data = NSData(contentsOfFile: path)  

使用初始化方法的话,我们就不需要面临自动释放的问题了,每次在超过作用域后,自动内存管理都将为我们处理好内存相关的事情。
转载自:http://www.csdn.net/article/2015-03-04/2824102

xcode提示App Transport Security has blocked a cleartext HTTP (http://) resource load的解决办法

今天开发中,遇到下问题,Xcode提示如下:
“App TransportSecurity has blocked a cleartext HTTP (http://) resource load since it isinsecure. Temporary exceptions can be configured via your app's Info.plistfile.”
简而言之:ATS禁止了HTTP的明文传输,因为它不安全。可以修改Info.plist文件,让它临时允许明文传输。
解决办法:
在Info.plist文件中添加"App Transport SecuritySettings", Type为"Dictionary",再添加"Allow Arbitray Loads", Type 为"Boolean",“Value”为“YES”即可。
转载自:http://www.zhimengzhe.com/IOSkaifa/1852.html

ios互斥锁

//
//  ViewController.swift
//  多线程
//
//  Created by admin on 16/2/17.
//  Copyright © 2016年 jin. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    var ticketsNumber = 20
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        let threadA = NSThread(target: self, selector: "buyTicket", object: nil)
        threadA.name = "售票员A"
        threadA.start()
        let threadB = NSThread(target: self, selector: "buyTicket", object: nil)
        threadB.name = "售票员B"
        threadB.start()
    }
    // 模拟卖票
    func buyTicket()
    {
        /**
        注意点:
        1.锁定的代码尽量少
        2.加锁范围内的代码同一时间只允许一个程序执行
        3.继承自NSObject的类都可以作为互斥锁的参数
        4.要保证所有的线程访问到这个锁,并且所有的线程访问的都是同一个锁对象
        */
        while(self.ticketsNumber > 0)
        {
            sleep(1)
            // 锁
            objc_sync_enter(self)
            print(NSThread.currentThread().name! + "卖出了\(self.ticketsNumber)号票")
            self.ticketsNumber--
            // 解锁
            objc_sync_exit(self)
        }
    }
}