zoukankan      html  css  js  c++  java
  • swift的一些知识点(不断完善中)

    首先,隆重推荐文章http://www.infoq.com/cn/articles/swift-brain-gym-optional swift 烧脑体操!目前有4篇文章,说的都很好!

    1. 应该充分利用swfit的新特性

    比如如果按照oc里的习惯,调用一个delegate中都optional函数应该这样写

    if delegate != nil && delegate!.respondsToSelector("downloadProgress:progress:"){
                delegate!.downloadProgress!(self, progress: totalProgress)
    }

    先检查是不是nil,再检查是否实现了方法,而swift应该这样写

            delegate?.downloadProgress?(self, progress: totalProgress)

    简单了许多!

    2. Optional 和 as? as!

    
    

            class Foo{

    
    

            }

    
    

            class SubFoo:Foo{

    
    

            }

    
    

            let foo:SubFoo? = SubFoo()



    if
    let realfoo = foo as! SubFoo? { //1 print(realfoo) } if let realfoo = foo as? SubFoo? { //2 print(realfoo) } if let realfoo = foo as! SubFoo! { //3 print(realfoo) } //if let realfoo = foo as! SubFoo { //4 // print(realfoo) //} if let realfoo = foo as? SubFoo { //5 print(realfoo) }

    if let realfoo = foo as? SubFoo { //6

    
    

        print(realfoo)

    
    

    }

    
    
    
     

    下面是具体输出

    SubFoo
    Optional(SubFoo)
    SubFoo
    SubFoo

    SubFoo
     

    这里,第四个是错误的写法,如果打开,会提示错误

     Initializer for conditional binding must have Optional type, not 'SubFoo'

    就是说,foo as! SubFoo 返回的不是optional,就是SubFoo类型。

    在对比上面的例子,就可以总结出,foo as! SubFoo 返回的就是 !号后面的类型的数据;而foo as? SubFoo? 返回的是 ?号后面类型的optional类型,这里可以看第二条,返回的是SubFoo?的optional型,解包后,得到了SubFoo?类型。

    说到这里,我们再看看optional类型,

    public enum Optional<Wrapped> : ExpressibleByNilLiteral 

    其实,它是一个enum。 说到enum,在c语言里就有,但是在c语言中,它仅仅是int型的另一种写法,方便编码人员明白其代表的意义。但是在swift中,enum得到了极大的拓展。

    为什么要使用enum类型?就是其中的每个case类型,具有某种抽象上的关联,讲他们统一放在一个enum中,可以让定义的变量从这些case类型中选出需要的一个,方便编程。

    首先,enum 可以指定raw属性对应的存储类型,比如:

    enum Suit:Int {
        case spades, hearts, diamonds, clubs
    }

    Suit.clubs.rawValue的值就是3,注意Suit.clubs可不是3. Suit.spades, Suit.hearts,Suit.clubs,Suit.diamonds它们都是 Suit类型。如果不使用rawValue属性,它们就一个enum对象,不是整形,也不是字符串。当使用print输出这个对象时,系统会自动把这个对象转化为字符串对象,系统提供了默认的enum类型对象转化为string方法,就是case后面定义的名字。比如Suit.clubs在print中的输出就是clubs。如果你不喜欢这种输出,可以让定义的enum类型实现CustomStringConvertible协议,自定义转化为string时的输出。

    如果不指定raw的属性,却对case赋值,就会有如下错误:

    再如:

    enum Suit:String {
        case spades, hearts, diamonds, clubs
    
    }

    Suit.clubs.rawValue的值就是 clubs。

    当不指定统一的raw类型时,可以在case中分开指定。

    比如下例:

    enum ServerResponse{

        case result(String, String)

        case failure(String)

        case testCase(AnyObject)

    }

    let test = ServerResponse.testCase(NSObject())

    switch test {

    case let .result(sunrise, sunset):

        print("Sunrise is at (sunrise) and sunset is at (sunset).")

    case let .failure(message):

        print("Failure...  (message)")

    case let .testCase(obj):

        print("test (obj)")

    }

     从这个例子,我们可以看出,其实swift的enum,就如同在每个case里多定义了一个叫做raw指针,可以指向具体对象,极大地拓展了c语言中的enum。所以即使同属于一个enum,raw所指向的类型也会大有不同!

    附上一个自定义输出内容的代码:

    enum Rank: Int, CustomStringConvertible { //这里看出 可以使用一个类型--代表rawValue的类型,多个协议--代表这个enum的特性,去定义enum
        case ace = 1
        case two, three, four, five, six, seven, eight, nine, ten
        case jack, queen, king
        
        var description: String {
            switch self {
            case .ace:
                return "A"
            case .jack:
                return "J"
            case .queen:
                return "Q"
            case .king:
                return "K"
            default:
                return String(self.rawValue)
            }
        }
    }

    看过了enum,我们再回头看看optional的部分定义:

    public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    
      /// In code, the absence of a value is typically written using the `nil`
      /// literal rather than the explicit `.none` enumeration case.
      case none
    
      /// The presence of a value, stored as `Wrapped`.
      case some(Wrapped)
    }
    /// A type that can be initialized using the nil literal, `nil`.
    ///
    /// `nil` has a specific meaning in Swift---the absence of a value. Only the
    /// `Optional` type conforms to `ExpressibleByNilLiteral`.
    /// `ExpressibleByNilLiteral` conformance for types that use `nil` for other
    /// purposes is discouraged.
    ///
    /// - SeeAlso: `Optional`
    public protocol ExpressibleByNilLiteral {
    
        /// Creates an instance initialized with `nil`.
        public init(nilLiteral: ())
    }

    我截取了定义的一部分。可以看出这里使用了模板,有2个case,其中some的rawValue是一个Wrapped(模板)类型指针,指向具体的数据。none这个case,就代表了空对象,也就是我们在其他语言里常用到的null。在swift的代码里,常用nil代替Optional<Wrapped>.none这种复杂的写法,但是我们可以看出,Optional.none才真正是swift中的空类型。

    说到这里,再谈一下在optional里常用到的符号 ! 

    这个叹号和optional类型连用时有2种情况:

    第一种:出现在类型声明中,举一个特殊的例子:

    class Person{
    public
    init!()
    }

    这个初始化函数的返回值就是用 ! 号标识的。它表示,返回值是一个optional类型,并且,在访问这个变量时,会自动进行解包,访问对应的raw值.

    let person1 = Person()这里的 person1就是 optional类型。

    另外,变量的赋值,无法触发自动解包操作,变量仍然会取optional类型,比如

    let person2 = person1 ,这里的person2 也是optional类型。

    第二种,进行具体的解包操作:

    接上面的例子,let person2 = person1!,这里,person2的类型就是Person类型,不再是optional类型了。

    那么所谓的自动解包是在什么时候解包呢?

    答案是:调用这个对象中的方法或属性的时候。比如:

     test不需要解包符号,而test2后必须写解包符号。


    3.关于swift引入的Computed Properties概念

    今天看了Salesforce的sdk,发现了如下的demo代码:

    #import "SObjectData.h"
    
    @interface SampleRequestSObjectData : SObjectData
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSString *contactId;
    @property (nonatomic, copy) NSString *contactName;
    @property (nonatomic, copy) NSString *productId;
    @property (nonatomic, copy) NSString *productName;
    @property (nonatomic, copy) NSString *deliveryDate;
    @property (nonatomic, copy) NSNumber *quantity;
    @property (nonatomic, copy) NSString *status;
    @property (nonatomic, copy) NSDictionary *authorizedUsers;
    @property (nonatomic, copy) NSArray *userRecords;
    @property (nonatomic, copy) NSArray *attachments;
    
    @end
    
    
    //
    //  SampleRequestSObjectData.m
    //  SFDCOfflinePoc
    //
    //  Created by PAULO VITOR MAGACHO DA SILVA on 1/24/16.
    //  Copyright © 2016 Topcoder Inc. All rights reserved.
    //
    
    #import "SampleRequestSObjectData.h"
    #import "SampleRequestSObjectDataSpec.h"
    #import "SObjectData+Internal.h"
    #import <SmartSync/SFSmartSyncConstants.h>
    
    @implementation SampleRequestSObjectData
    
    + (SObjectDataSpec *)dataSpec {
        static SampleRequestSObjectDataSpec *sDataSpec = nil;
        if (sDataSpec == nil) {
            sDataSpec = [[SampleRequestSObjectDataSpec alloc] init];
        }
        return sDataSpec;
    }
    
    #pragma mark - Property getters / setters
    
    - (NSString *)name {
        return [self nonNullFieldValue:kSampleRequestNameField];
    }
    
    - (void)setName:(NSString *)name {
        [self updateSoupForFieldName:kSampleRequestNameField fieldValue:name];
    }
    
    - (NSString *)contactId {
        return [self nonNullFieldValue:kSampleRequestContactField];
    }
    
    - (void)setContactId:(NSString *)contactId {
        [self updateSoupForFieldName:kSampleRequestContactField fieldValue:contactId];
    }
    
    - (NSString *)contactName {
        return [[self nonNullFieldValue:kSampleRequestContactQueryField] objectForKey:@"Name"];
    }
    
    - (NSString *)productId {
        return [self nonNullFieldValue:kSampleRequestProductField];
    }
    
    - (void)setProductId:(NSString *)productId {
        [self updateSoupForFieldName:kSampleRequestProductField fieldValue:productId];
    }
    
    - (NSString *)productName {
        return [[self nonNullFieldValue:kSampleRequestProductQueryField] objectForKey:@"Name"];
    }
    
    - (NSString *)deliveryDate {
        return [self nonNullFieldValue:kSampleRequestDeliveryDateField];
    }
    
    - (void)setDeliveryDate:(NSString *)deliveryDate {
        [self updateSoupForFieldName:kSampleRequestDeliveryDateField fieldValue:deliveryDate];
    }
    
    - (NSString *)quantity {
        return [self nonNullFieldValue:kSampleRequestQuantityField];
    }
    
    - (void)setQuantity:(NSString *)quantity {
        [self updateSoupForFieldName:kSampleRequestQuantityField fieldValue:quantity];
    }
    
    - (NSString *)status {
        return [self nonNullFieldValue:kSampleRequestStatusField];
    }
    
    - (void)setStatus:(NSString *)status {
        [self updateSoupForFieldName:kSampleRequestStatusField fieldValue:status];
    }
    
    - (NSDictionary *)authorizedUsers {
        return [self nonNullFieldValue:kSampleRequestAuthorizedUsersField];
    }
    
    - (void)setAuthorizedUsers:(NSDictionary *)authorizedUsers {
        [self updateSoupForFieldName:kSampleRequestAuthorizedUsersField fieldValue:authorizedUsers];
    }
    
    - (NSArray *)attachments {
        return [self nonNullFieldValue:kSampleRequestAttachmentsField];
    }
    
    - (void)setAttachments:(NSArray *)attachment {
        [self updateSoupForFieldName:kSampleRequestAttachmentsField fieldValue:attachment];
    }
    
    
    - (NSArray *) userRecords {
        int totalSize = [[self.authorizedUsers objectForKey:@"totalSize"] intValue];
        if (totalSize > 0) {
            return [self.authorizedUsers objectForKey:@"records"];
        }
        return nil;
    }
    
    @end

    通过代码,可以看出,声明的几个@property 其实没有对每个property对应的真实变量进行读写操作,而是通过自定义的get,set方法对其他的数据进行操作,但是系统会不会自动建立那些没用的真实变量呢?从代码上是看不出了。而且从声明的地方也看不出这些property的特殊性,不注意还真容易误解。

    swift的Computed Properties,解决了这个问题:

    struct Rect {
        var origin = Point()
        var size = Size()
        var center: Point {
            get {
                let centerX = origin.x + (size.width / 2)
                let centerY = origin.y + (size.height / 2)
                return Point(x: centerX, y: centerY)
            }
            set(newCenter) {
                origin.x = newCenter.x - (size.width / 2)
                origin.y = newCenter.y - (size.height / 2)
            }
        }
    }

    这里的center,有自定义的get,set方法,就明确地指出了它的目的不是为了保存一个值,而是“provide a getter and an optional setter to retrieve and set other properties and values indirectly.”  

    这个写法就比以前的oc写法要好上很多啊!

    4. swift中同名函数(多态?)

    func test(one:NSString) -> NSString{
        return "aaa"
    }
    
    func test(one:Int) -> NSString{
        return "bbbb"
    }

    上面是2个函数!他们的区别仅仅是输入参数类型不同!

    5.

    swift 中不叫做类属性,叫类型属性,因为在swift中,struct 和enum也是可以有这种属性的,叫类属性明显不准。

    顺便复习一下,java 和 c++中类方法和类变量是用 static 关键字声明的。

    static在c语言中有2个作用,写在函数体里面时,作用同上面的几种情况,表示静态的意思。但是写在函数体外边时,是防止其他全局变量同名,也阻止了外部文件对这个变量的引用。

    oc 中类方法用+标记,类变量与c语言中的一样。一般而言,使用static声明,并另外写函数提供访问方法。

    swift中的值类型(struct,enum)保持了这个传统,使用static关键字。但在类中发明了class这个关键字。

    6.

    今天写了delegate,遇到以下问题:

    这里protocol的写法有问题,如果delegate指向一个实现了某个协议对象的引用,在oc里是这样写delegate的类型 id<protocol>,而在swift中,没有这种写法,应该像上面那样直接写出协议名,因此,协议声明应该这样写:

    protocol MyPickerViewDelegate: NSObjectProtocol {
    
        func pickerConfirm(content:String)
    }

     这也是因为,除了class 外,struct和enum也能实现协议,但是他们都是值类型,不是引用类型,如果想使用weak,那么必须先让协议符合class的要求!

  • 相关阅读:
    作业 20181030-3互评Alpha版本
    Alpha阶段事后诸葛亮会议记录
    Alpha发布用户使用报告
    20181023-2 贡献分配
    作业 20181016-1 Alpha阶段贡献分配规则
    Scrum立会报告+燃尽图(十月三十日总第二十一次)
    OC中时间函数的使用
    OC中的集合详解
    面向对象的概念详解(转)
    集中类
  • 原文地址:https://www.cnblogs.com/breezemist/p/4307299.html
Copyright © 2011-2022 走看看