美文网首页
Swift 学习笔记

Swift 学习笔记

作者: KyleBing | 来源:发表于2017-10-10 10:27 被阅读212次

    Swift

    常规

    • 任何变量都要有初始值
    • switch case 不需要 break

    Class vs Struct

    • class 可以继承,struct不可以
    • class 使用时最终指向struct 本身,而struct是实例
    • 如果struct中的一个方法要改变内容,需要在前面添加 mutating 关键字

    enum

    enum Operation{
        case constant( Double )                     //可以设置关联值
        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 {}
    
    • 方法在声明的时候,参数可能有内外两个名字
    • 省略某个参数名字用 _ 代替
    • 如果只留一个参数名,那么这个名字既是内名字,也是外名字

    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 类型的数据

    遍例

    for (key, value) in dict {}
    

    String

    遍例

    for c: Character in s.Characters {}
    
    // 字符数:人类识别的字符数
    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
    • 便捷初始化方法直接初始化方法 两种
    • 直接初始化方法,必须调用分类的直接初始化方法
    • 在调用父类初始化方法之前,必须初始化所有自定义的元素
    • 在修改父类元素之前,必须先调用父类初始化方法

    继承

    • 如果不使用任何 Init 方法,将继承所有的

    Any & AnyObject

    if let vc = ViewController as? UIViewController {}
    

    UserDefaults

    是个小型的数据库,一般用来存储用户设置,在启动应用的时候就存在,不能放太大的东西。

    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
    

    创建自己的 UIView

    class MyUIView: UIView{
        override func draw(_ rect: CGRect) {
            self.drawPath()
        }
        func drawPath(){
            // 创建曲线对象
            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()
    

    让自己创建的类能在 StoryBoard 中显示并编辑

    需要在类前面添加 @IBDesignable
    在变量前面添加 @IBInspectable

    添加 @IBInspectable 的变量必须明确指定数据类型

    @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 vcdetail 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 已经准备好
        // prerare for segue 准备好
        // 但是 几何 上还没有准备好。 bounds 之类的
    }
    
    func viewWillAppear( _ animated: Bool ){
        // 更新 UI
        // 放一些真正要实现的东西 
    }
    
    func viewDidAppear ( _ animated: Bool ){
        // 已经出现在屏幕上,适合作一些动画
    }
    
    func viewWillDisappear ( _ animated: Bool ){
        // 清理一些将不再显示在屏幕上的内容
        // 不要做一些耗时的操作,不然会使应用迟顿
    }
    
    

    几何学变化操作

    func viewWillLayoutSubviews(){
        // 比如旋转的时候 
    }
    
    func viewDidLayoutSubviews(){
    
    }
    
        // 旋转时的动画
    func viewWillTransition(
        to size: CGSize,
        with coordinator: UIViewControllerTransitionCoordinator
    )
    
    
    func awakeFromNib(){
        
    }
    

    内存管理 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 扩展

    作为一个类的扩展,扩展一个类的代码,不需要重写,就是在原类的基础上添加东西。

    • 不能添加已经存在的 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

    同文件内可见的 private

    多线程 Multithreading

    queue

    queue 可以是单线程的,也可以是多线程的

    Main Queue

    • 一个特殊的线程 main queue
    • 所有的 UI 活动都在这个 queue 上执行,也只在这个上执行
    • 其它非 UI 活动都不能出现在这个 queue
    • Main queue 上的线程执行时是按顺序的

    Global Queues

    Getting a queue

    // Getting a main queue
    let mainQueue = DispatchQueue.main
    
    let backgroundQueue = DispatchQueue.global ( qos: DispatchQoS )
    DispatchQoS.userInteractive // 高优先级,只做一些快、短 的进程
    DispatchQoS.userInitiated       // 高优先级,占用一点时间
    DispatchQoS.background          // 不被用户所初始化,可以做一些慢的操作
    DispatchQoS.utility             // 低优先级,长期运行于后台的进行
    
    

    在 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 时出现
    或者给它传送 becomeFirstResponder 的信息
    将其隐藏 resignFirstResponder

    func textFieldShouldReturn ( sender: UITextField ) -> Bool{
    // 当键盘回车按下时,需要往这个方法中发送
    sender.resignFirstResponder ()
    }

    控制键盘

    发送给继承了 UITextInputTraits 协议的类 ( 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 中添加一个静态变量,方便获取 `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 可以直接获取 变量数据
    
    // 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

    1. entity to request
    2. NSSortDescriptor
    3. NSPredicate
    //.1
    let request: NSFetchRequest <Tweet> = Tweet.fetchRequest()
    
    //.2
    let sortDescriptor = NSSortDescriptor(
        key: "screenName", asending: true,
        selector: #selector(NSString.localizedStandardCompare(_:))
        // 这个方法是根据本地化的语言来判断顺序
    )
    
    //.3
    let searchString = "foo"
    let predicate = NSPredicate(format:"text contains[c] %@", searchString)
    let predicate = NSPredicate(format: "tweeter.screenName = %@", "username")
    request.predicate = predicate
    
    //.执行
    let recentTweeters = try? context.fetch (request)
    // 返回的是 nil Array
    
    for user in recentTweeters{
        print("fetched user name \(user.name)")
        // 未使用其中的数据的时候,结果是空的
    }
    

    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
        }
    }
    

    创建 FetchRaultController

    let frc = NSFetchedResultsController<Tweet>(
                    fetchRequest    :   request,
        managedObjectContext    :   context,
            sectionNameKeyPath  :   keyThatSaysWhichArrtributeIsTheSctionName,
                        acheName    :   "MyTwitterQueryCache")
    

    AlertAction

    • Add new UIAlertController
    • new alertAction
    • add alertAction to UIAlertController

    AutoLayout

    Compact Regular

    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”
    //  动画出现在结果完成后
    //  结果已经是0了,动画是在结果出现后慢慢呈现的
    

    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 在存储自定义数据时,需要:

    1. 在自定义类中实现 NSCoding 的两个方法, 解密init(coder aCoder: NSCoder) 加密encode(with aCoder: NSCoder)
    2. 用里面的方法来处理自己类的变量 解密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")
        }
    
    
    1. 先将数据用 NSKeyedArchiver 转换一下,再存储
    let archivedData = NSKeyedArchiver.archivedData(withRootObject: DataVAR) // 先把在存储的变量归档
    UserDefaults.standard.set(archivedData, forKey: "KEY") // 再存入 UserDefaults
    
    1. 取出的时候 NSKeyedUnarchiver
    if let rawData = (UserDefaults.standard.object(forKey: "KEY") as? Data) {
         原始数据 =  NSKeyedUnarchiver.unarchiveObject(with: rawData) as! 存入的数据类型
    }
    

    相关文章

      网友评论

          本文标题:Swift 学习笔记

          本文链接:https://www.haomeiwen.com/subject/izqvyxtx.html