程序员iOS Developer

Swift高级语法

2017-03-30  本文已影响476人  Jimmy木

主要总结一些平时遇到的疑难点,在此总结出来,持续更新。可能有些误导大家的地方,欢迎指正。

难点

实现<code>read-only</code>:
Swift中的属性没有对应的实例变量,必须自己创建。
struct Point {
private var _y: Int?
var y:Int { return _y }
}
🔥set
存储属性,主要存储值。
设置存储属性时,必须实现计算属性。

  struct Point {
     var y: Int?
     var x: Int?
     var loation:(Int?, Int?) {
        get { return (x, y) }
        set {
           x = newValue.0
           y = newValue.1
       }
     }
  }

🔥willSet、didSet是观察器
<code>willSet</code>在新值设置之前调用,传入默认参数<code>newValue</code>。
<code>didSet</code>在新值设置之后调用,传入默认参数<code>oldValue</code>。
观察器观察的不止是对象本身,对象的某个属性的值改变也会触发观察器。
⚠️设置观察期后就不能实现计算属性和存储属性。

函数

Curring

柯里化:《Advanced Swift》中提出的一种通过写方法模板来快速实现方法的机制。让我们的方法更加动态化,可以整合系统方法。

Curring将接受多个参数的函数,转化成每次接受一个参数的调用序列。

Curring主要是一种新的表现形式,主要看个人喜好,并没有什么很特别的地方。

下面介绍两种Curring的方法:

关键字

闭包

闭包是一个引用类型的代码块,可以用作函数的参数或者返回值,可以捕获上下文的任何常量和变量。

全局函数:都是有命名的闭包,但是不能捕获任何值。
嵌套函数:都是有命名的闭包,并且能够捕获当前上下文的值。
闭包表达式:闭包表达式都是无名闭包,可以捕获上下文的值。

默认情况下,闭包会捕获附近作用域中的常量和变量,并使用强引用指向它们。你可以通过一个捕获列表来显式指定它的捕获行为。

捕获列表在参数列表之前,由中括号括起来,里面是由逗号分隔的一系列表达式。一旦使用了捕获列表,就必须使用 in 关键字,即使省略了参数名、参数类型和返回类型。

  //值捕获
  var a = 0 
  var b = 0 
  let closure = { [a] in     
     print(a, b)
  } 
  a = 10 
  b = 10 
  closure() // 打印 “0 10”
  //引用捕获
  class SimpleClass {    
       var value: Int = 0
  }
  var x = SimpleClass() 
  var y = SimpleClass() 
  let closure = { [x] in    
       print(x.value, y.value)
  } 
  x.value = 10 
  y.value = 10 
  closure() // 打印 “10 10”

在捕获列表中,也可以将任意表达式的值绑定到一个常量上。该表达式会在闭包被创建时进行求值,闭包会按照指定的引用类型来捕获表达式的值。例如:

  // 以弱引用捕获 self.parent 并赋值给 parent
  myFunction { [weak parent = self.parent] in print(parent!.title) }

运算符重载

  1. 定义类

    struct HMPoint {
       var x = 0.0
       var y = 0.0
    

    }

  2. 重载二目运算符

    func +(a: HMPoint, b: HMPoint) -> HMPoint {
       let c = HMPoint(x: a.x + b.x, y: a.y + b.y)
       return c
    }
    
    let va = HMPoint(x: 10, y: 12)
    let vb = HMPoint(x: 23, y: 8)
    
    let vc = va + vb
    vc.x  // 33
    
  3. 重载前缀运算符

    prefix func -(a:HMPoint) -> HMPoint{
        return HMPoint(x: -a.x, y: -a.y)
    }
    let vz = -va
    vz.x //-10
    
  4. 重载后缀运算符

    postfix func ++(a: HMPoint) -> HMPoint {
         return HMPoint(x: a.x + 1, y: a.y+1)
    }
    var vn = vz++
    vn.x // 11
    
  5. 重载+=

    //使用inout改变输入参数
    func +=(left: inout HMPoint, right: HMPoint) {
            left = left + right
    }
    vn += vz
    vn.x
    
  6. 修改运算符优先级

使用<code>infix</code>修改优先级

   infix operator +-: AdditionPrecedence

   extension HMPoint {
        static func +- (left: HMPoint, right: HMPoint) -> HMPoint {
                return HMPoint(x: left.x + right.x, y: left.y - right.y)
        }
   }
   let dassa = vn +- vz
   dassa.x

下标编程

通过<code>subscript</code>关键字可以使普通类同步通过下标访问数据。

struct Subscript {
    var number: Int?
    subscript(index: Int) -> Int {
       return (number ?? 1 ) * index
    }
}

struct Subscript {
      var number: Int?
      subscript(index: Int) -> Int {
          get {
             return (number ?? 1) * index
          }
          set(newValue) {
             number = newValue
          }
     }
}
//带多个值的下标
struct Point {
      subscript(x: Int, y: Int) -> Int {
          return x + y
      }
}
var p = Point()
p[1,3]
//带n个下标
struct Path {
    subscript(x: Int...) -> Int {
        return x.count
    }
}
var path = Path()
path[1,2,3]
//带多维下标
struct Pad {
    var xx: Int
    subscript(x: Int) -> Pad {
        return Pad(xx: x)
    }
}

var pad = Pad(xx: 1)
pad[1][2][3].xx

设计模式

内存管理

http://www.jianshu.com/p/f2f47a472947

Runtime

  1. 扩展属性

    extension UIView {
        private struct AssociatedKeys{
           static var loadingViewKey:UIView?
        }
    
        var loadingView: UIView? {
            get {
               return objc_getAssociatedObject(self, &AssociatedKeys.loadingViewKey) as? UIView
            }
            set {
                 if let newValue = newValue {
                     newValue.backgroundColor = .red
                     objc_setAssociatedObject(self, &AssociatedKeys.loadingViewKey, newValue,objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
                 }
            }
        }
    }
    
  2. 交换方法

    class TestSwizzling : NSObject {
           dynamic func methodOne() -> Int {
               return 1
           }
    }
    
    extension TestSwizzling {
          //在 Objective-C 中,我们在 load() 方法进行 swizzling。但Swift不允许使用这个方法。
          override class func initialize() {
               let originalSelector = #selector(TestSwizzling.methodOne);
               let swizzledSelector = #selector(TestSwizzling.methodTwo);
     
               let originalMethod = class_getInstanceMethod(self, originalSelector);
               let swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
     
               method_exchangeImplementations(originalMethod, swizzledMethod);
               }
    
         func methodTwo() -> Int{
                // swizzling 后, 该方法就不会递归调用
                return methodTwo() + 1
         }
    }
    
    var c = TestSwizzling()
    print(c.methodOne())  //2
    print(c.methodTwo())  //1
    
  3. 获取属性和方法名

    fun allPropertyNamesAndValues(cls:AnyClass) ->[String: AnyObject] {
        var count: UInt32 = 0
        let properties = class_copyPropertyList(cls, &count)
    
        var resultDict: [String: AnyObject] = [:]
        for var i = 0; i < Int(count); ++i {
               let property = properties[i]
     
               // 取得属性名
              let name = property_getName(property)
              if let propertyName = String.fromCString(name) {
              // 取得属性值
                 if let propertyValue = self.valueForKey(propertyName) {
                      resultDict[propertyName] = propertyValue
                 }
             }
        }
       return resultDict
    }
    
    func allMethods() {
         var count: UInt32 = 0
         let methods = class_copyMethodList(Person.self, &count)
    
         for var i = 0; i < Int(count); ++i {
             let method = methods[i]
             let sel = method_getName(method)
             let methodName = sel_getName(sel)
             let argument = method_getNumberOfArguments(method)
     
            print("name: (methodName), arguemtns: (argument)")
         }
    }
    

GCD

单元测试

同OC
第三方库中都有很全面的单元测试代码,可以学习一下。

第三方库

上一篇下一篇

猜你喜欢

热点阅读