|  
 作者:fengsh998 
 原文地址:http://blog.csdn.net/fengsh998/article/details/28904115 
  
 转载请注明出处 
  
 如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢! 
 
    
  可选类型、隐式可选类型  在swift中,可选类型其根源是一个枚举型,里面有None和Some两种类型。其实所谓的nil就是Optional.None,非nil就是Optional.Some,然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用Optional的时候要拆包(从enum里取出来原始值)的原因,也是PlayGround会把Optional值显示为类似{Some "hello world"}的原因,这里是enum Optional的定义:    
  
  
   enumOptional<T>:LogicValue,Reflectable{ caseNonecaseSome(T) init() init(_some:T)   funcgetLogicValue()->Bool   funcmap<U>(f:(T)->U)->U? funcgetMirror()->Mirror } 
 
    语法使用“?”操作符及"!"号操作符  如:“var optionalString: String? ="Hello"optionalString == nil
 
 var optionalName: String? = "John Appleseed"
 var greeting = "Hello!"
 if let name = optionalName {
 greeting = "Hello,(name)"
 }”
 
 大家把optionalName改为nil时看一下会有什么结果?按照理解,应该是? = 后的为可选值,即当我们的的变量为nil时,这里如果有?=操作,则会使用?=后的值作为默认值,而不会为nil. 这个等有环境时,验证一下。
  经验证:  分别执行:  varoptional:String?="okgood"; 
   println(optional)  输出为:  ok good  与      varoptional:String? 输出为:
      nil 
    来看下!号,官方释为隐式解包:主要用在一个变量/常量在定义瞬间完成之后值一定会存在的情况。这主要用在类的初始化过程中。  官风例子:    letpossibleString:String?="Anoptionalstring." 
   println(possibleString!)//prints"Anoptionalstring." letassumedString:String!="Animplicitlyunwrappedoptionalstring." println(assumedString)  实说话,你照这个例子运行,还真看不出什么,得不出什么结论。因此我自己Z磨着,试着理解一个英文翻译。再自己操刀练习。得出下面的一些结论。    varoptionVariables:String? 
  //varoptionVariables:Optional<Int> letvalue=optionVariables?.hashValue/*optionVariables是可选类型的字符串,如果optionVariables是nil,则hashValue也为nil如果optionVariables不为nil,hashValue就是strValue字符串的哈希值到这里我们看到了?的两种使用场景:1.声明Optional值变量2.用在对Optional值操作中,用来判断是否能响应后面的操作*///对于可选类型变量,不能直接进行操作,否则会报错//lethashval=optionVariables.hashValue//'String?'doesnothaveamembernamed'hashValue'//因此要访问值就需要解包,解包有两种//第一种:使用iflet/varxxx=iflethv=optionVariables {//runok; }//第二种:使用!号 lethv=optionVariables!.hashValue//这里的!表示“我确定这里的的strValue一定是非nil的,尽情调用吧”,比如这种情况:ifoptionVariables{ lethashv=optionVariables!.hashValue }//{}里的optionVariables一定是非nil的,所以就能直接加上!,强制拆包(unwrap)并执行后面的操作 
 
    凡在变量或常量后加上?的都是一个可选变量/可选常量凡在变量或常量后加上!的都是隐式可选变量/常量,有点难理解,首先该变量或常量满足可选类型,其主要是可被当生一般的变量/常量来使用,而不需要每次都验证是否有值。
  注:如果一个隐式解包的可选类型不包含一个实际值,那么对它的访问会抛出一个运行时错误。在变量/常量名后面加!的情况也是一样的。
    varpossibleString:String?="Anoptionalstring." 
  分析:首先 possibleString 因后面带上了?说明这是一个可选的,同时前面加上var为变量,所以这是一个可选类型的变量。其可选值为 "An optional string." 再来看执行println后,可以看出输出为 An optional string. 这点很明显。再来看一下把println这句改一下改为 (即在可选变量后面加上一个!号。)//possibleString=nil println(possibleString)      <spanstyle="font-size:18px;">println(possibleString!) 
 这里结果与没有加!号时是完全一样的,输出为An optional string.    好,现在重点来了,这是很关键的一个测试。把possibleString = nil 这句注释放开让其动行,再分别来看一下println带!和不带!的情况:  情况一:不带!号时,输出为nil .    <spanstyle="font-size:18px;">varpossibleString:String?="Anoptionalstring." 
  情况二:再来看一下带!号 possibleString=nil println(possibleString)</span>      println(possibleString!) 
 这时运行到这句println就会crash了。会报  fatal error: Can't unwrap Optional.None错误。    在情况一时,为什么不会报错,是因为这是一个可选变量当变量为nil时,自动验证是否有可选的值,有则使用可选值,在情况二,加上!访问符来访问possibleString 变量,但由于possibleString设为了nil (等价于var possibleString: String?) 其并没有包含一个实际值,所以抛异常.同样对于下面使用!号来声明的也一样道:    <spanstyle="font-size:18px;">varassumedString:String!="Animplicitlyunwrappedoptionalstring." 
  同样会报:fatal error: Can't unwrap Optional.None assumedString=nil println(assumedString!)</span> 
 
    如果你定义了一个可选类型并且没有给予初始值的时候,会默认设置为nilvar surveyAnswer: String? // 初自动设置为nil
 注: Swift 的nil不同于Object-C中的nil. Object-C中,nil是一个指针指向不存在的对象。Swift中,nil不是指针而是一个特定类型的空值。任何类型的可选变量都可以被设为nil,不光是指针。
 
  在swift中作何变量/常量的声明都必须带有初始值,否则就要声明为可选型。  即var btn:UIButton 这样是编译报错的。因些必须改为带初始化的如:    varbtn2 :UIButton=UIButton()或者使用? 和! 来约束。    因此常常声明可选或隐式可选变量如:  var btn :UIButton?   // 默认btn = nil  var edt :UITextField! // 默认edt = nil  至于什么时候使用?什么情况下使用!号来约束变量,我还没有悟出真真原理。  因此借助于自己的几次验证来帮助大家理解。    <spanstyle="font-size:18px;">varbtn:UIButton? 
   varbtn2:UIButton=UIButton() varbtn3:UIButton!//运行会报错fatalerror:Can'tunwrapOptional.None因btn=nil btn!.tintColor=UIColor.blackColor() btn!.imageEdgeInsets=UIEdgeInsets(top:1,left:2,bottom:3,right:4) btn!.frame=CGRectMake(0,50,40)//运行正常 btn2.tintColor=UIColor.blackColor() btn2.imageEdgeInsets=UIEdgeInsets(top:1,right:4) btn2.frame=CGRectMake(0,40)//运行会报错fatalerror:Can'tunwrapOptional.None因btn3=nil btn3.tintColor=UIColor.blackColor() btn3.imageEdgeInsets=UIEdgeInsets(top:1,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> btn3.frame=CGRectMake(0,40)</span> 因此为了运行期不crash可以改为如下:
     ifvartmpbtn=btn 
  或者//运行正常 btn2.tintColor=UIColor.blackColor() btn2.imageEdgeInsets=UIEdgeInsets(top:1,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> btn2.frame=CGRectMake(0,0); background-color:inherit">//运行会报错fatalerror:Can'tunwrapOptional.None因btn3=nilifvartmpbtn=btn { btn3.tintColor=UIColor.blackColor() btn3.imageEdgeInsets=UIEdgeInsets(top:1,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> btn3.frame=CGRectMake(0,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> }</span>     ifbtn 
  注:如果一个可选类型存在没有值的可能的话,不应该使用解包(隐式)可选类型。这种情况下,一定要使用正常的可选类型。ifbtn3 }</span>    这句话我个人是这样理解的,如var view:UIView。当我的整个应用中或整个类中不可能存在view = nil的情况时可以设置为var view:UIView! 否则就可声明为var view:UIView? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |