import UIKit
protocol Emitterable {
}
//這里的 where Self : UIViewController 意思是對使用該效果必須繼承自UIViewController
extension Emitterable where Self : UIViewController {
func start() {
// 1.創(chuàng)建發(fā)射器
let emitter = CAEmitterLayer()
// 2.設(shè)置發(fā)射器的位置
emitter.emitterPosition = CGPoint(x: view.bounds.width * 0.5, y: -60)
// 3.開啟三維效果
emitter.preservesDepth = true
// 4.創(chuàng)建例子, 并且設(shè)置例子相關(guān)的屬性
// 4.1.創(chuàng)建例子Cell
let cell = CAEmitterCell()
// 4.2.設(shè)置粒子速度
cell.velocity = 150
cell.velocityRange = 100
// 4.3.設(shè)置例子的大小
cell.scale = 0.7
cell.scaleRange = 0.3
// 4.4.設(shè)置粒子方向
cell.emissionLongitude = CGFloat(M_PI_2)
cell.emissionRange = CGFloat(M_PI_2 / 2)
// 4.5.設(shè)置例子的存活時(shí)間
cell.lifetime = 6
cell.lifetimeRange = 1.5
// 4.6.設(shè)置粒子旋轉(zhuǎn)
cell.spin = CGFloat(M_PI_2)
cell.spinRange = CGFloat(M_PI_2 / 2)
// 4.6.設(shè)置例子每秒彈出的個(gè)數(shù)
cell.birthRate = 20
// 4.7.設(shè)置粒子展示的圖片
cell.contents = UIImage(named: "good6_30x30")?.cgImage
// 5.將粒子設(shè)置到發(fā)射器中
emitter.emitterCells = [cell]
// 6.將發(fā)射器的layer添加到父layer中
view.layer.addSublayer(emitter)
}
func stop() {
/*
for layer in view.layer.sublayers! {
if layer.isKind(of: CAEmitterLayer.self) {
layer.removeFromSuperlayer()
}
}
*/
view.layer.sublayers?.filter({ $0.isKind(of: CAEmitterLayer.self)}).first?.removeFromSuperlayer()
}
}
調(diào)用很簡單:
class ViewController: UIViewController , Emitterable {
override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.start()
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.stop()
}
}
}
效果:

Snip20161212_5.png
import UIKit
/************************** 字典定義 *****************************/
// Swift中字典的類型Dictionary
// 不可變字典使用let修飾
// 可變字典使用var修飾
// 注意:字典在創(chuàng)建時(shí)使用[]
let dict : Dictionary = ["name" : "JJCoder", "age" : 18] as [String : Any]
// dict = ["name" : "lmj", "age" : 20]
let dict1 : Dictionary<String, AnyObject> = ["name" : "jack" as AnyObject, "age" : 20 as AnyObject]
// 開發(fā)中常見寫法
let dict2 : [String : AnyObject] = ["name" : "jack" as AnyObject, "age" : 22 as AnyObject]
// 類型推導(dǎo)
let dict3 = ["name" : "jjcoder", "age" : 26] as [String : Any]
// 可變字典
var dict4 = [String : AnyObject]()
/************************** 對可變字典的操作 *****************************/
// 1.在字典中添加元素
dict4["name"] = "lmj" as AnyObject?
dict4
dict4["age"] = 26 as AnyObject?
dict4
dict4["height"] = 1.74 as AnyObject?
dict4
// 2.從字典中移除元素
let age = dict4.removeValue(forKey: "age")
// 3.修改字典中的值
// 注意:通過一個(gè)鍵來修改字典中的值,如果存在這個(gè)鍵則修改.如果不存在就會添加新的鍵值對
dict4["weight"] = 62.0 as AnyObject?
dict4
dict4["height"] = 1.74 as AnyObject?
dict4
// 4.獲取值
// let height = dict4["height"]! as! Double
let height = dict4["height"]!
print(height)
/************************** 對可變字典的遍歷 *****************************/
// 1.遍歷字典中所有的鍵
for key in dict4.keys {
print(key)
}
// 2.遍歷字典中所有的值
for value in dict4.values {
print(value)
}
// 3.遍歷字典中的鍵值對
for (key, value) in dict4 {
print(key)
print(value)
}
/************************** 字典的合并 *****************************/
var d1 = ["name" : "jjcoder", "age" : 20] as [String : Any]
var d2 = ["height" : 174, "phoneNum" : "+86 15210100335", "name" : "majianjie"] as [String : Any]
// 兩個(gè)字典,即時(shí)類型一致也不可以彼此相加
// var d3 = d1 + d2
// 合并過程中,如果沒有對應(yīng)的鍵,添加對應(yīng)的鍵值對
// 如果有隊(duì)要你管的鍵,則修改原有的值
for (key, value) in d1 {
d2[key] = value
}
>Swift中的元組
import UIKit
// 元祖也是一個(gè)數(shù)據(jù)集合,可以在集合中定義一組數(shù)據(jù)
// 元祖的定義使用:(元素1,元素2)
("1001", "JJCoder", 19, 1.74)
(id : "1001", name : "張三", age : 26, height : 1.74)
// 用一個(gè)數(shù)據(jù)類型來描述網(wǎng)絡(luò)請求錯(cuò)誤
// errorCode/errorInfo
[404, "Not Found"] as [Any]
["errorCode" : 404, "errorInfo" : "Not Found"] as [String : Any]
// 用元祖描述錯(cuò)誤信息
let error = (404, "Not Found")
error.0
error.1
let error1 = (errorCode : 404, errorInfo : "Not Found")
error1.errorCode
error1.errorInfo
switch (error1) {
case (404, "Not Found"):
print("沒有找到host")
default :
print("其他錯(cuò)誤")
}
let (errorCode2, errorInfo2) = (404, "Not Found")
errorCode2
errorInfo2
map : 可以對數(shù)組中的每一個(gè)元素做一次處理
如果求一個(gè)數(shù)組中字符串的長度可以用 map來處理
//方法1
let array = ["Objective-C", "HTML", "CSS"]
//定義方法 返回傳入的字符串的長度
func calcuCount(string: String) -> Int {
return string.characters.count
}
//使用 打印
print(array.map(stringCount))
// 方法2
print(fruits.map{return $0.characters.count})
reduce:可以對數(shù)組中的元素進(jìn)行計(jì)算
// 將數(shù)組中的每個(gè)字符串用‘-’拼接
let array = ["Objective-C", "HTML", "CSS"]
func appendString(string1: String, string2: String) -> String {
return string1 == "" ? string2 : string1 + "-" + string2
}
// reduce方法中的第一個(gè)參數(shù)是初始值
print(array.reduce("第一個(gè)字符串", appendString))//打印第一個(gè)字符串-Objective-C-HTML-CSS
// $0表示計(jì)算后的結(jié)果, $1表示數(shù)組中的每一個(gè)參數(shù)
print(array.reduce("", {
return $0 == "" ? $1 : $0 + "-" + $1
}))
//打印 Objective-C-HTML-CSS
filer:過濾,可以對數(shù)組中的元素按照某種規(guī)則進(jìn)行一次過濾
let stringArray = ["MJ-C", "Swift", "Cocos2d-x", "Python", "JavaScript"]
func stringCountLess10(string: String) -> Bool {
return string.characters.count < 10
}
stringArray.filter(stringCountLess10)
stringArray.filter({string -> Bool in
return string.characters.count < 10
})
// $0表示數(shù)組中的每一個(gè)元素
stringArray.filter{
return $0.characters.count < 10
}
后期會陸續(xù)更新....
flatmap 可以把數(shù)組繼續(xù) '切割'
// 用flatMap
let arrayFlatMap = arraya.flatMap { $0 }
print(arrayFlatMap)
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
>Swift類構(gòu)造函數(shù)
import UIKit
/*
1.自定義構(gòu)造函數(shù)時(shí)會覆蓋原有的構(gòu)造函數(shù)
如果不希望覆蓋,則可以明確的將原來的構(gòu)造函數(shù)寫出
*/
class Person {
var name : String = ""
var age : Int = 0
init() {
}
init(name : String, age : Int) {
self.name = name
self.age = age
}
init(dict : [String : AnyObject]) {
if let name = dict["name"] as? String {
self.name = name
}
if let age = dict["age"] as? Int {
self.age = age
}
}
}
// 1.使用init()構(gòu)造函數(shù)創(chuàng)建對象
let p = Person()
p.name = "jjcoder"
p.age = 18
// 2.使用init(name : String, age : Int)創(chuàng)建對象
let p1 = Person(name: "mjj", age: 19)
// 3.通過init(dict : [String : AnyObject])方法創(chuàng)建對象
let p2 = Person(dict: ["name" : "mjj" as AnyObject, "age" : 26 as AnyObject])
>Swift中的可選類型
import UIKit
// nil 只能賦值給可選類型,不能賦值給其他的任意類型
// var name : String = "why"
// name = nil
var view : UIView = UIView()
// view = nil
/*
// 1.可選類型如何定義
var name : Optional<String> = nil
// 2.給可選類型進(jìn)行賦值
name = Optional("123")
*/
// 1.可選類型如何定義
var name : String? = nil
// 2.給可選類型進(jìn)行賦值
name = "123"
// 3.取出可選類型中值 : 需要對可選類型進(jìn)行解包
// print(name)
print(name!)
// 4.可選類型 + ! --> 強(qiáng)制解包
// 如果可選可選類型為nil,那么強(qiáng)制解包程序就會崩潰
// 5.可選綁定 : 1> 判斷可選類型有沒有值, 如果沒有值,那么{}不執(zhí)行 2> 如果有值, 會先對name進(jìn)行解包, 并且將解包后的結(jié)果賦值給前面的標(biāo)識符
if let name = name {
print(name)
}
Swift中的類型分為兩種 :
- 值類型
每個(gè)值類型的實(shí)例都擁有各自唯一的數(shù)據(jù),通常它們是結(jié)構(gòu)體,枚舉或元組
Array、String和Dictionary都是值類型
- 引用類型
引用類型的實(shí)例共享它們的數(shù)據(jù),通常是一個(gè)類。
class 是引用類型
區(qū)別?
值類型最基本的特征就是復(fù)制在賦值、初始化和傳遞參數(shù)過程中的數(shù)據(jù),并為這個(gè)數(shù)據(jù)創(chuàng)建一個(gè)獨(dú)立
的實(shí)例
下面舉2個(gè)粟子:??
// 值類型例子
struct MJJ { var data: Int = 1 }
var a = MJJ()
var b = a // 把a(bǔ)賦值給b
a.data = 42 // a被改變了, b卻沒有
println("\(a.data), \(b.data)") // prints "42, 1"
// 引用類型的例子
class JJCoder { var data: Int = -1 }
var x = JJCoder()
var y = x // x被復(fù)制給了y
x.data = 4 // x指向的數(shù)據(jù)被修改了 (同時(shí)y也被修改了)
println("\(x.data), \(y.data)") // prints "4, 4"
其實(shí)是隱式地創(chuàng)建了一個(gè)共享的實(shí)例。在賦值后,兩個(gè)實(shí)例指向了同一塊數(shù)據(jù),所以當(dāng)修改其中一個(gè)實(shí)例數(shù)據(jù)的時(shí)候,另一個(gè)實(shí)例的數(shù)據(jù)也被修改了
安全性方面考慮??
選擇值類型而不是引用類型的一個(gè)主要原因是能讓你的代碼變得更加簡單。你在任何情況下用一個(gè)值類型,都能夠假設(shè)你的其他代碼不會使它改變,這通常在多線程環(huán)境中很有用,如果一個(gè)線程中使用的數(shù)據(jù)被另一個(gè)線程給意外的修改了,這通常會產(chǎn)生非常嚴(yán)重的Bug,且相當(dāng)難以調(diào)試。
由于只有當(dāng)你需要修改數(shù)據(jù)時(shí)兩者的區(qū)別才會得到體現(xiàn),所以當(dāng)你的實(shí)例不會對數(shù)據(jù)進(jìn)行修改的時(shí)候,值類型和引用類型看起來是完全相同的。
你也許會想,寫一個(gè)完全不可變的類,這或許是有價(jià)值的,使用Cocoa的NSObject能簡化這個(gè)過程,并且能很好地保持原有的語義?,F(xiàn)在,你能通過使用不可變的存儲屬性,以及避免暴露修改數(shù)據(jù)的接口,從而在Swift里實(shí)現(xiàn)一個(gè)不可變的類。事實(shí)上,大多數(shù)的Cocoa類,比如NSURL等,都被設(shè)計(jì)為不可變的類,然而,Swift當(dāng)前并沒有提供任何語言機(jī)制去強(qiáng)制申明一個(gè)類不可改變(比如子類化就能修改一個(gè)類的實(shí)現(xiàn)),只有結(jié)構(gòu)體和枚舉才是強(qiáng)制不可變的。
如何抉擇:??
使用值類型:
1. 通過使用==去比較實(shí)例的數(shù)據(jù)
2. 想得到一個(gè)實(shí)例的獨(dú)立副本
3. 數(shù)據(jù)在多線程環(huán)境下被修改
使用引用類型(比如使用一個(gè)類):
1. 通過使用===去判斷兩個(gè)實(shí)例是否恒等
2. 你想要?jiǎng)?chuàng)建一個(gè)共享的,可變的對象
iOS默認(rèn)是不支持播放GIF圖片的,但是系統(tǒng)也沒有禁止播放它,該有的API還是有的,下面就 來一發(fā)吧!
一定要導(dǎo)入ImageIO 這個(gè) 庫
//首先你得有個(gè)imageview吧~~~~~
@IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// 1??.在本地加載Gif圖片(不要放在imageassert中,其實(shí)也放不進(jìn)去~~`), 并且轉(zhuǎn)成Data類型(這里不再寫swift語法,guard 做一下校驗(yàn)...)
guard let path = Bundle.main.path(forResource: "demo.gif", ofType: nil) else { return }
guard let data = NSData(contentsOfFile: path) else { return }
// 2??. 將data轉(zhuǎn)成CGImageSource對象,返回CGImageSource
guard let imageSource = CGImageSourceCreateWithData(data, nil) else { return }
//3??通過CGImageSource可以拿到分解了多少張圖片(看成是一幀一幀的)
let imageCount = CGImageSourceGetCount(imageSource)
// 4??遍歷所有的圖片
var images = [UIImage]()
var totalDuration : TimeInterval = 0
for i in 0..<imageCount {
// 3??.1??取出圖片
guard let cgImage = CGImageSourceCreateImageAtIndex(imageSource, i, nil) else { continue }
let image = UIImage(cgImage: cgImage)
if i == 0 {
imageView.image = image
}
//3??.2??加入到一個(gè)images的數(shù)組中
images.append(image)
// 3??.3??取出持續(xù)的時(shí)間(這里記住就可以了)
guard let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, i, nil) as? NSDictionary else { continue }
guard let gifDict = properties[kCGImagePropertyGIFDictionary] as? NSDictionary else { continue }
guard let frameDuration = gifDict[kCGImagePropertyGIFDelayTime] as? NSNumber else { continue }
totalDuration += frameDuration.doubleValue
}
// 4??.給imageView設(shè)置屬性
imageView.animationImages = images
imageView.animationDuration = totalDuration
imageView.animationRepeatCount = 0
// 5??.開始播放
imageView.startAnimating()
}