Swift
常規(guī)
- 任何變量都要有初始值
-
switch case
不需要break
Class vs Struct
- class 可以繼承,struct不可以
- class 使用時最終指向struct 本身封锉,而struct是實例
- 如果struct中的一個方法要改變內(nèi)容绵跷,需要在前面添加 mutating 關鍵字
enum
enum Operation{
case constant( Double ) //可以設置關聯(lián)值
case unaryOperation( (Double) -> Double )
}
Tuple
let x: (String, Int, Double) = (“hello”, 5, 0.85)
let (word, number, value) = x
print(word)
let x: (w: String, n: Int, v: Double) = (“hello”, 5, 0.85)
print (x)
fun getLocation -> (x: Int, y: Int){
return (120, 34)
}
let location = getLocation
print ( location.x )
Range
- …
- ..<
…
let array = [1, 2, 3, 4]
let a = array [ 2…3 ] // [3, 4]
let b = array [ 2..<3 ] // [3]
for i in 1..<10 {}
stride
for i in stride (from: 1, through: 10, by: 0.2){}
Methods
func setValue(from firstPlace: Int, to secondPlace: Int) -> Bool {}
- 方法在聲明的時候,參數(shù)可能有內(nèi)外兩個名字
- 省略某個參數(shù)名字用 _ 代替
- 如果只留一個參數(shù)名成福,那么這個名字既是內(nèi)名字碾局,也是外名字
Properties
var property: Int = 42{
willSet { newVlaue 是新值}
didSet { oldValue 是舊值}
}
可計算的變量
var recWidth: CGFloat {
get { return bounds.size.width / 2 }
set { recWidth = newValue }
}
// 如果只需要 get 方法,就不需要寫外面的 get 了奴艾,像這樣
var recWidth: CGFloat {
return bounds.size.width / 2
}
lazy
直到被用到時净当,才會被初始化
lazy var brain = CalculatorBrain()
Array
var a = Array<String>()
var a = [String] ()
遍例
for animal in a {}
過濾元素
filter (includeElement: (T) -> Bool) -> [T]
let bigNumbers = [2, 34, 12, 45].filter({$0 > 20})
// 轉換元素
map(transform: (T) -> U) -> [U]
let stringified: [String] = [1, 2, 3].map({String($0)}) // [“1”, “2”, “3”]
Dictionary
var dict = Dictionary <String, Int> ()
var dict = [String: Int] ()
從字典中取值的時候,返回的是該值的 Option 類型的數(shù)據(jù)
遍例
for (key, value) in dict {}
String
遍例
for c: Character in s.Characters {}
// 字符數(shù):人類識別的字符數(shù)
let count = s.characters.count
// 字符串中找哪個字符的位置
let firstSpace: String.Index = s.characters.index (of: “ ”)
// 字符可以加減
var greeting = “hello”
greeting += “ there”
print ( greeting ) // “hello there”
var endIndex: String.Index
func hasPrefix ( String ) -> Bool //有前綴
func hasSuffix ( String ) -> Bool //有后綴
其它類
NSObject
NSObject : Objective-C 的根類
Date
Data
Init
初始化方法
- 里面可以重設
let
變量值 - 必須初始化里面的所有變量
var
let
- 有
便捷初始化方法
和直接初始化方法
兩種 - 直接初始化方法蕴潦,必須調(diào)用分類的直接初始化方法
- 在調(diào)用父類初始化方法之前像啼,必須初始化所有自定義的元素
- 在修改父類元素之前,必須先調(diào)用父類初始化方法
繼承
- 如果不使用任何 Init 方法品擎,將繼承所有的
Any & AnyObject
if let vc = ViewController as? UIViewController {}
UserDefaults
是個小型的數(shù)據(jù)庫埋合,一般用來存儲用戶設置,在啟動應用的時候就存在萄传,不能放太大的東西甚颂。
func set ( Any? forKey: String )
func object ( forKey: String ) -> Any?
// 用法
let defaults = UserDefaults.standard // 獲取UserDefaults
defaults.set ( “Kyle”, forKey: “name” ) // 設置值
defaults.set ( 25, forKey: “age” )
defaults.set ( “Kyle”, forKey: “name” )
func double( forKey: String ) -> Double //獲取值
func array( forKey: String ) -> [Any]?
// 存儲
// 自動存儲的蜜猾,如果想手動存儲
if !defaults.synchronize () {}
Assertions
assert ( ()->Bool, “message” ) //如果返回false, 打印 Message
UI相關
所有圖形相關的東西都是用CG____ 如Float
就是 CGFloat
CGFloat
let cgf = CGFloat(Double.pi)
CGSize
var cgs = CGSize(width: 200, height: 100)
cgs.width += 1
cgs.height += 5
CGPoint
var cgp = CGPoint(x: 4.5, y: 8.5)
CGRect
var cgr = CGRect(origin: cgp, size: cgs)
var cgr_2 = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(60.0), height: CGFloat(35.0))
cgr.minX // 最小x
cgr.minY // 最小y
cgr.intersects(cgr_2) // -> Bool 是否與第二個Rect相交
cgr.intersection(cgr_2) //
//cgr.contains(point: CGPoint) // 包含某個點
//cgr.contains(rect2: CGRect) // 包含某個Rect
addSubview()
let ui = UIView(frame: cgr)
ui.backgroundColor = UIColor.brown // CGColor
var ui2 = UIView(frame: cgr_2)
ui2.backgroundColor = UIColor.orange
ui.addSubview(ui2)
// 每個點有多少像素
ui.contentScaleFactor
// Frame & Bounds
ui.bounds // 邊界,可旋轉
ui.frame // 容器
ui.center
創(chuàng)建自己的 UIView
class MyUIView: UIView{
override func draw(_ rect: CGRect) {
self.drawPath()
}
func drawPath(){
// 創(chuàng)建曲線對象
let path = UIBezierPath()
// 畫線
path.move(to: CGPoint(x: 80, y: 50))
path.addLine(to: CGPoint(x: 140, y: 150))
path.addLine(to: CGPoint(x: 10, y: 150))
// 關閉路徑
path.close()
UIColor.orange.setFill() // UIColor 的方法
UIColor.brown.setStroke() // UIColor 的方法
path.lineWidth = 5.0 // 設置曲線粗細
path.fill() // UIBezierPath 的方法
path.stroke() // UIBezierPath 的方法
}
}
let triPath = MyUIView()
讓自己創(chuàng)建的類能在 StoryBoard 中顯示并編輯
需要在類前面添加 @IBDesignable
在變量前面添加 @IBInspectable
添加
@IBInspectable
的變量必須明確指定數(shù)據(jù)類型
@IBDesignable
class Face: UIView {
@IBInspectable
var scale: CGFloat = 0.9
@IBInspectable
var eyeOpen: Bool = false
@IBInspectable
var smileRatio: Double = -1.0 // 1.0 | -1.0
}
手勢
UINavigationController
- rootViewController
操作MVC
var viewControllers: [UIViewController] ? { get set }
- tab bar, 從左到右依次排列
- split view振诬,
[0]
是主視圖祷嘶,[1]
是詳細信息視圖 - navigation controller,
[0]
是根視圖
確定自己在哪個MVC中
var tabBarController: UITabBarController? { get }
var splitViewController: UISplitViewController? { get }
var navigationController: UINavigationController? { get }
比如:要得到 split vc
的 detail vc
可以這樣獲取
if let detail: UIViewController? = splitViewController?.viewControllers[1]
Segues
一些Segues
- Show Segue
- Show Detail Segue
- Modal Segue
- Popover Segue
identifier
prepare segue
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier{
switch identifier {
case "show graph":
if let vc = segue.destinationViewController as? GraphController {
vc.property1 = ...
}
default: break
}
}
}
prepare 的時候涂邀,outlet 還是 nil
Life Cicle
- awakeFromNib
- segue prepared
- outlets get set
- viewDidLoad
- viewWillAppear
- viewVillDisappear
- viewWillLayoutSubviews()
override func viewDidLoad(){
// outlet 已經(jīng)準備好
// prerare for segue 準備好
// 但是 幾何 上還沒有準備好替久。 bounds 之類的
}
func viewWillAppear( _ animated: Bool ){
// 更新 UI
// 放一些真正要實現(xiàn)的東西
}
func viewDidAppear ( _ animated: Bool ){
// 已經(jīng)出現(xiàn)在屏幕上,適合作一些動畫
}
func viewWillDisappear ( _ animated: Bool ){
// 清理一些將不再顯示在屏幕上的內(nèi)容
// 不要做一些耗時的操作辫呻,不然會使應用遲頓
}
幾何學變化操作
func viewWillLayoutSubviews(){
// 比如旋轉的時候
}
func viewDidLayoutSubviews(){
}
// 旋轉時的動畫
func viewWillTransition(
to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator
)
func awakeFromNib(){
}
內(nèi)存管理 Memory Management
- strong
- weak
- unowned
stong
default value
weak
only optional can be weak
如果沒人指向我清钥,就把我設為 nil
unowned
Thrown Errors
func save() thrown{}
do {
try ...
} catch let error{
thrown error
// rethrown errors
}
Extensions 擴展
作為一個類的擴展,擴展一個類的代碼放闺,不需要重寫祟昭,就是在原類的基礎上添加東西。
- 不能添加已經(jīng)存在的 func
- extension 不能存儲任何變量怖侦,只能有計算值
extension UIViewController {
var contentViewController: UIViewController {
if let navcon = self as? UINavigationController {
return navcon.visibleViewController
} else {
return self
}
}
}
if let myvc = segue.destinationViewController.contentViewController as? MyVC { ... }
Protocols
protocols 只是一些 func 和 properties 的集合
- protocols 是個類型篡悟,像 Int String
使用 protocols
protocol SomeProtocol : InheritedProtocol1, InheritedProtocol2 {
var someProperty: Int { get set }
func aMethod( arg1: Double, anotherArgument: String ) -> SomeType
mutating func changeIt ()
init ( arg: Type )
}
// 如果只想讓 class 繼承這個 protocol
protocol SomeProtocol : class, InheritedProtocol1, InheritedProtocol2
// Class
class SomeClass : SuperclassOfSomeClass, SomeProtocol, AnotherProtols{
}
// Enum
enum SomeEnum : SuperclassOfSomeClass, SomeProtocol, AnotherProtols{
}
// SomeStrunct
strunct SomeStruct : SuperclassOfSomeClass, SomeProtocol, AnotherProtols{
}
filePrivate
同文件內(nèi)可見的 private
多線程 Multithreading
queue
queue 可以是單線程的,也可以是多線程的
Main Queue
- 一個特殊的線程
main queue
- 所有的
UI
活動都在這個 queue 上執(zhí)行匾寝,也只在這個上執(zhí)行 - 其它非
UI
活動都不能出現(xiàn)在這個queue
中 -
Main queue
上的線程執(zhí)行時是按順序的
Global Queues
Getting a queue
// Getting a main queue
let mainQueue = DispatchQueue.main
let backgroundQueue = DispatchQueue.global ( qos: DispatchQoS )
DispatchQoS.userInteractive // 高優(yōu)先級搬葬,只做一些快、短 的進程
DispatchQoS.userInitiated // 高優(yōu)先級艳悔,占用一點時間
DispatchQoS.background // 不被用戶所初始化急凰,可以做一些慢的操作
DispatchQoS.utility // 低優(yōu)先級,長期運行于后臺的進行
在 queue 中添加代碼
多進程簡單來說就是往 queue 中添加 closures
// 放在 queue 中
queue.async { ... }
// 暫停當前 queue 直到 closure 運行完
queue.sync { ... }
Getting a non-global queue
let serailQueue = DispatchQueue ( label: "MyserialQ" )
Example
let session = URLSession(configuration: .default)
if let url = URL(string: "http://kylebing.cn/pics/Sketch.jpg"){
let task = session.dataTask(with: url) { (data: Data?, response, error) in
// do something with data
DispatchQueue.main.async {
// do UI stuff here
}
}
task.resume() // Run task
}
UITextField
鍵盤會在 UITextFild
變成 first responder
時出現(xiàn)
或者給它傳送 becomeFirstResponder
的信息
將其隱藏 resignFirstResponder
func textFieldShouldReturn ( sender: UITextField ) -> Bool{
// 當鍵盤回車按下時很钓,需要往這個方法中發(fā)送
sender.resignFirstResponder ()
}
控制鍵盤
發(fā)送給繼承了 UITextInputTraits
協(xié)議的類 ( UITextFiled 已繼承該類 )
var autocapitalizationType: UITextAutocapitalizationType
var autocorrectionType: UITextAutocorrectionType // .yes .no
var returnKeyType: UIReturnKeyType // go, search, google, done, etc.
var isSecureTextEntry: Bool // for passwd, for example
var keyboardType: UIKeyboardType // ascii, url, phonepad, etc.
// 鍵盤上面可以有輔助工具欄香府,自定義
var inputAccessoryView: UIView //
Others
var clearsOnBeginEditing: Bool
var adjustsFontSizeToFitWidth: Bool
var minimumFontSize: CGFloat
var placeholder: String?
var background/disabledBackground: UIImage?
var defaultTextAttributes: [String: Any]
UITableViewController
設置 Seperator
tableview.seperatorStyle = .none
Core Data
// 獲取 Core Data
let container = ( UIApplication.shared.delegate as? AppDelegate ).persistentContainer
// 直接在 AppDelegate 中添加一個靜態(tài)變量,方便獲取 `persistentContainer`
static var persistentContainer: NSPersistentContainer {
return (UIApplication.shared.delegate as! AppDelegate ).persistentContainer
static var viewContext: NSManagedObjectContext {
return persistentContainer.viewContext
}
let coreDataContainer = AppDelegate.persistentContainer
let context = AppDelegate.viewContext
// Insert Data
let sweet: NSManageObject = NSEntityDescription.insertNewObject ( forEntityName: "Tweet", into: context ) // 新建一個元素码倦,元素屬性都為 nil
let sweet = Sweet(viewContext) // 如果定義了類企孩,可以直接這個新建一個變量
func value (forKey: String) -> Any?
func setValue(Any?, forKey: String)
let username = tweet.value(forKeyPath: "tweeter.name") as? String
// CoreData 自動建立相同名稱的 class 可以直接獲取 變量數(shù)據(jù)
// Codegen 選擇 Category / Extension
// 所有變量的相關定義都會在 Extension 中
// 此時,可以自定義自己的關于這個 CoreData Entity 的 Class
// Save Data
do {
try context.save()
} catch {
// deal with error
}
// Deletion
managedObjectContext.delete(? object: tweet)
func prepareForDeletion(){
}
let context = AppDelegate.viewContext
if let tweet = Tweet( context: context ){
tweet.text = ...
tweet.created = Date()
let joe = TwitterUser(context. tweet.managedObjectContext)
tweet.tweeter = joe
tweet.twetter.name = "Joe Schmo"
}
Query: NSFetchRequest
- entity to request
- NSSortDescriptor
- NSPredicate
//.1
let request: NSFetchRequest <Tweet> = Tweet.fetchRequest()
//.2
let sortDescriptor = NSSortDescriptor(
key: "screenName", asending: true,
selector: #selector(NSString.localizedStandardCompare(_:))
// 這個方法是根據(jù)本地化的語言來判斷順序
)
//.3
let searchString = "foo"
let predicate = NSPredicate(format:"text contains[c] %@", searchString)
let predicate = NSPredicate(format: "tweeter.screenName = %@", "username")
request.predicate = predicate
//.執(zhí)行
let recentTweeters = try? context.fetch (request)
// 返回的是 nil Array
for user in recentTweeters{
print("fetched user name \(user.name)")
// 未使用其中的數(shù)據(jù)的時候袁稽,結果是空的
}
CoreData Thred Safaty
context.performBlock{
//ensure code in this do in the right Q
}
AppDelegate.presistentContainer.performBackgroundTask {context in
try? context.save()
}
NSFetchResultController
連接 NSFetchRequest 和 UITableView
如果 CoreData 變化勿璃,會自動更新 UITableView
var fetchedResultsController = NSFetchedRusultsController...
func numberOfSectionInTableView( sender: UITableView) -> Int {
return fetchedResultsController?.sections?.count ?? 1
}
func tableView(sender: UITableView, numberOfRowsInSection section: int) -> Int{
if let sections = fetchResultsController?.sections, sections.count > 0 {
return sections[section].numberOfObjects
} else {
return 0
}
}
創(chuàng)建 FetchRaultController
let frc = NSFetchedResultsController<Tweet>(
fetchRequest : request,
managedObjectContext : context,
sectionNameKeyPath : keyThatSaysWhichArrtributeIsTheSctionName,
acheName : "MyTwitterQueryCache")
AlertAction
- Add new UIAlertController
- new alertAction
- add alertAction to UIAlertController
AutoLayout
C
ompact R
egular
iPhone
P: W:C H:R
L: W:C H:C
iPhone 6 7
P: W:C H:R
L: W:R H:C
Animation
UIView Animation
myView.alpha = 1.0
UIView.animate(withDuration: 3.0,
delay: 2.0,
options: [.curveLinear],
animations:{ myView.alpha = 0.0 },
completion: {if $0{ myView.removeFromSuperview() } })
print( myView.alpha )
// 會輸出 “0”
// 動畫出現(xiàn)在結果完成后
// 結果已經(jīng)是0了,動畫是在結果出現(xiàn)后慢慢呈現(xiàn)的
UIViewAnimationOptions
- beginFromCurrentState
- allowUserInteraction
- layoutSubviews
- repeat
- autoreverse
- overrideInheritedDuration
- overrideInheritedCurve
- allowAnimattedContent
- curveEaseInEaseOut
- curveEaseIn
- curveLinear
Entire View animation view transition
// Flip
UIviewAnimationOptions .transitionFlipFrom{ Left, Right, Top, Bottom }
.transitionCrossDissolve
.transitionCurl { Up, Down}
// e.g.
UIView.transition ( with: myPlayingCardView,
duration: 0.5,
option: [.transitionFlipFromLeft],
animations:{ code in here},
completion: nil )
Hierarchy animation from A to B
// e.g.
UIView.transition ( from: UIView,
to: UIview,
duration: 0.5,
option: UIViewAnimationOptions,
completion: ((finished: Bool) -> Void)? )
Alerts and Ction Sheets
UIApplication
let myApp = UIApplication.shared
func open(URL)
func canOpenURL(URL) -> Bool
func (un)registerForRmoteNotifacation()
Get more time when enter Background Mode
func beginBackgroundTask(withExpirationHanlder:(() -> Void)?) -> UIBackgroundTaskIdentifier
func endBackgroundTask(UIBackgroundTaskIdentifier)
Turning on "Network in use" spinner on the status bar
var isNetworkActivityIndicatorWisible: Bool
Finding out about things
var backgroundTimeRemaining: TimeInterval { get }
var preferredContentSizeCategory: UIContentSizeCatergory { get }
// big fonts or small fonts
var applicationState: UIApplicationState { get }
// foreground, background, active
Info.plist
Persistence
UserDefaults
Core Data
Archiving
SQLite
File System
Notification
Timer
private weak var timer: Timer?
timer = Timer.scheduledTimer(withTimerInterval: 2.0, repeats: true){
// code
}
timer.invalate
NSKeyedArchiver and UserDefaults
UserDefaults 在存儲自定義數(shù)據(jù)時推汽,需要:
- 在自定義類中實現(xiàn)
NSCoding
的兩個方法补疑, 解密init(coder aCoder: NSCoder)
加密encode(with aCoder: NSCoder)
- 用里面的方法來處理自己類的變量 解密
aCoder.decodeObject/.decodeInteger/...(forKey: "KEY")
, 加密aCoder.encode(VAR, forKey: "KEY")
required init?(coder aDecoder: NSCoder) {
super.init()
if let reds = aDecoder.decodeObject(forKey: "redBalls") as? [Int] {
redBalls = reds
} else {
redBalls = []
}
blueBall = aDecoder.decodeInteger(forKey: "blueBall")
}
func encode(with aCoder: NSCoder) {
aCoder.encode(redBalls, forKey:"redBalls")
aCoder.encode(blueBall, forKey: "blueBall")
}
- 先將數(shù)據(jù)用
NSKeyedArchiver
轉換一下歹撒,再存儲
let archivedData = NSKeyedArchiver.archivedData(withRootObject: DataVAR) // 先把在存儲的變量歸檔
UserDefaults.standard.set(archivedData, forKey: "KEY") // 再存入 UserDefaults
- 取出的時候
NSKeyedUnarchiver
if let rawData = (UserDefaults.standard.object(forKey: "KEY") as? Data) {
原始數(shù)據(jù) = NSKeyedUnarchiver.unarchiveObject(with: rawData) as! 存入的數(shù)據(jù)類型
}