Swift與Objective-C的對比

WWDC 2014上蘋果再次驚世駭俗的推出了新的編程語言Swift 雨燕, 這個消息會前沒有半點風聲的走露。消息發佈當時,會場一片驚呼,相信全球看直播的碼農們當時也感受腦殼被敲了一記悶棍吧。因而熬夜學習了Swift大法, 越看越想高呼 」 Swift大法好!「java

 

程序員,最講究的就是實事求是和客觀,下面就開始對比兩種語言。c++

 

首先要強調的是,Swift絕對不是解釋性語言,更不是腳本語言,它和Objective-C,C++同樣,編譯器最終會把它翻譯成C語言,也就是 說編譯器最終面對的其實都是C語言代碼( 這是千真萬確,無可置疑的!!!因此不要看它長的想腳本語言,其實它是比Java, C#要高效的多的C語言!!!),可是Swift的強大之處在於它站在全部語言的肩膀上,吸收全部語言的精華。程序員

 

這個系列咱們先談談幾個最基本的語法變化:objective-c

  1. Swift終於放棄了Objective-C那幺蛾子般的 [ obj method:x1 with:x2] 的語法,終於跟隨了大流,變成了obj.method( )的順眼模式。雖然對於Objective-C的程序員來講,這些[ ]看上去特顯酷 , 大家知道就是這個中括弧嚇跑了多少c++, java , c#的程序員嘛?因此說這個小小的變化,可讓蘋果的開發更平易近人,對有其餘開發語言基礎的人來講更友好。

但蘋果不會這麼自甘平庸,咱們知道Objective-C裏方法的調用有種語法是其餘主流語言沒有的,那就是標籤。咱們在使用java, C++, C, C#等語言時,若是使用 rect.set( 10, 20, 100, 500 ), 雖然在寫set方法的時候,IDE有提示四個形參的含義,但寫完後,這句代碼中10, 20, 100, 500是社麼意思? 因此代碼的可讀性就變的不好, 而Objective-C很完美的解決了這個問題 :編程

C代碼 複製代碼  收藏代碼
  1. [ rect setX:10 y:20 width:100 height:500 ]  
[ rect setX:10 y:20 width:100 height:500 ]

 

 

看看!多棒!Swift固然不會丟棄這麼好的傳統, 在Swift中是這個樣子的swift

C代碼 複製代碼  收藏代碼
  1. rect.set( 10, y:20, width:100, height:500 )  
rect.set( 10, y:20, width:100, height:500 )

 

 

對於調用方法時,標籤的使用須要注意如下兩點:c#

 

1)全局函數的調用,不可使用標籤api

  1. fun( 11, 22 , 33 ) //正確
  2. fun( n1:11, n2: 22, n3: 33 ) //錯誤

2 ) 類的函數,第一個參數不能夠加標籤 編程語言

  1. rect.set( 100, y:100, width:300, height: 200 ) //正確
  2. rect.set( x:100, y:100, width:300, height: 200 ) //錯誤

 

其實Swift中對類的定義和java, c#幾乎同樣,不再分頭文件和.m文件了。ide

一個類的定義語法以下:

C代碼 複製代碼  收藏代碼
  1. class Weapon  
  2. {  
  3.     var name:NSString  
  4.     var power:int  
  5.     init( name:NSString, power:int )  
  6.     {  
  7.         self.name = name  
  8.         self.power = power  
  9.     }  
  10.     func shoot( )  
  11. }  
class Weapon
{
    var name:NSString
    var power:int
    init( name:NSString, power:int )
    {
        self.name = name
        self.power = power
    }
    func shoot( )
}

 

注意:Swift中的語句不須要分號結束.

其次,終於有構造函數和析構函數了!!!Objective-C也有?no no no!!!

Objective-C中沒有構造函數,真正的構造函數是系統自動調用的,而不是強迫程序員去調用。之前要強迫程序員[ [ Obj alloc ] init ],如今終於終於終於系統自動調用了!

C代碼 複製代碼  收藏代碼
  1. Weapon weapon = Weapon( name:「人間大炮」, power: 100000000000 )  
Weapon weapon = Weapon( name:「人間大炮」, power: 100000000000 )

 

我沒有寫錯, 對的!如今和java,C#同樣!雖然weapon是一個指針,但不要寫那顆星號!!由於這顆星號嚇死過好多人!「 啥?指針?!!啊。。。。。」

 

C、 C++的程序員注意了,這個weapon對象不是分配在棧內存上的, 仍然是alloc出來的, 在堆上呢。

  1. 最期待的語法終於加入了!

對於override在Java,C++,Objective-C中都有問題,舉個栗子:

C代碼 複製代碼  收藏代碼
  1. @interface Weapon  
  2. -(void)shoot;  
  3. @end  
  4. @interface Gun : Weapon  
  5. -(void)Shoot;  
  6. @end  
@interface Weapon
-(void)shoot;
@end
@interface Gun : Weapon
-(void)Shoot;
@end

 

在大項目中常常會遇到這個問題,程序員的本意是但願覆蓋父類的shoot ,結果手潮。。。。寫成了Shoot , 這既沒有語法錯誤,也沒有邏輯錯誤,結果在

C代碼 複製代碼  收藏代碼
  1. Weapon*  currentWeapon = [ Gun new ];  
Weapon*  currentWeapon = [ Gun new ];

 

[currentWeapon shoot ] 中調用的倒是父類的shoot方法( 由於子類根本沒有覆蓋啦,子類大小寫不當心寫錯了 ), 這種小錯誤若是出如今超大型項目種還真是很難找呢!!如今,Swift終於解決這個問題啦! 子類覆蓋父類方法的時候,必定要在方法前寫上override :

C代碼 複製代碼  收藏代碼
  1. override func shoot{  
  2. }  
override func shoot{
}

 

這樣,編譯器一看方法前寫了override, 它就會在父類中去查找是否有shoot方法, 若是你寫錯成override func Shoot, 那編譯器就馬上能發現報錯啦!

 

系列(二)

 

系列一發表後,有人不一樣意個人關於 #swift會取代objective-c#的論點,在這裏我想強調兩點:

 

1)Swift其實就是Objective-C的文本變種,對於這門全新的語言,蘋果作的工做其實遠沒有咱們想像的艱鉅。LLVM編譯器作工做只是 先把swift翻譯成Objctive-C代碼,而後再把Objective-C代碼翻譯成C語言代碼,而後再把C語言代碼翻譯成彙編,最終翻譯成機器 碼。至於爲何編譯器廠商這麼繞,不直接把本身的語言翻譯成彙編和機器碼,那是因爲現有的語言編譯器(Objective-C, C )已經很是成熟,而高級語言間的文本轉換開發成本和維護成本都極其小。Swift爲何要翻譯成Objective-C,是因爲Swift仍然須要 Objective-C中辛苦構建的ARC,GCD 等環境。

 

2)既然Swift代碼最終會被LLVM翻譯成Objective-C, 那Swift語言還有什麼意義?想一想ARC剛出來的時候你們的反應吧,不少人和今天的反應同樣,認爲我是資深的objective-c馬仔了,我深諳內存 管理之道,不停的寫[ obj release ], [ obj autoRelease] 很牛,只有那些初學者纔會用ARC呢。結果就是不到一年,ARC統治了整個馬仔界,由於咱們馬仔關注的應該是業務邏輯,而不該該把精力分散在語法等低級問 題上,語法消耗咱們的時間越少,這門語言就越成功。

 

既然Swift其實就是Objective-C, 對入門者而言遠比Objective-C好學,對資深開發者來講又能節約不少無謂的低級重複的機械代碼(這些代碼在LLVM翻譯成Objective-C 時,編譯器自動幫你寫上)。我是想不出任何一點Swift不替換Objective-C的理由呢。

 

好吧,爭論放置一邊不表,咱們從頭來看swift到底進化到什麼程度。



1)語句不須要分號結束,變量若是有初始化就不須要類型

C代碼 複製代碼  收藏代碼
  1. var n = 22  
var n = 22

 

對於編譯器而言,既然你都初始化爲22了,它固然明白n是int , 你都打回車了, 它固然知道這是語句的結束,因此LLVM毫無壓力的把它翻譯成

C代碼 複製代碼  收藏代碼
  1. int n = 22;  
int n = 22;

 

固然對於多個語句放一行,那編譯器就沒有辦法了, 你仍是要用分號來結束語句。若是沒有初始化,你也能夠手工指定變量類型

C代碼 複製代碼  收藏代碼
  1. var n = 22; var hero:Hero  
var n = 22; var hero:Hero

 

因此看上去是無類型變量,實質上仍是強類型的( 編譯器給你作了 ).

若是是常量的話, 用let

C代碼 複製代碼  收藏代碼
  1. let PI = 3.1415926  
let PI = 3.1415926

 

這裏的PI 就是常量, 如今想一想,之前的強類型高級語言真是傻到無語啊,let PI = 3.1415926 , PI  都這麼明顯是個double, 爲啥還要程序員再寫double ?!

 

2)函數的定義

C代碼 複製代碼  收藏代碼
  1. func test( p1: int, p2: int )  
  2. {  
  3. }  
func test( p1: int, p2: int )
{
}

 

調用: test( 25 , 100 ) //注意:全局函數的調用,參數不能加標籤

若是有返回值, 返回類型用符號 「 -> 」 表示

C代碼 複製代碼  收藏代碼
  1. func  add( p1: int, p2 : int )->int  
  2. {  
  3.     return p1+p2  
  4. }  
func  add( p1: int, p2 : int )->int
{
    return p1+p2
}

 

3)類的定義

再也不分頭文件和m文件了!這點和java, C#如出一轍

C代碼 複製代碼  收藏代碼
  1. class Person  
  2. {  
  3.     var    name:String  
  4.     var    age = 0  
  5.     init( name:String , age:int )  
  6.     {  
  7.         self.name = name;  
  8.         self.age = age;  
  9.     }  
  10.     func description( )->String  
  11.     {  
  12.         return 「Name:\( self.name ) ; Age: \( age )」;  
  13.     }  
  14. }  
class Person
{
    var    name:String
    var    age = 0
    init( name:String , age:int )
    {
        self.name = name;
        self.age = age;
    }
    func description( )->String
    {
        return 「Name:\( self.name ) ; Age: \( age )」;
    }
}

 

注意終於有構造函數了!!init 是系統自動調用的, 不須要程序員手工調用。因此它寫起來和普通函數也有區別,前邊不能加func。 編譯器爲何要這樣作?由於若是init也容許前面加上func, 萬一程序員不當心把init函數名寫錯了, 寫成func Inot( ),編譯器就徹底不知道它是程序員想寫的構造函數。如今構造函數前不加func , 若是你寫成Inot( ) 。 編譯器一看前面沒有func知道你要寫構造,可函數名又不是init, 編譯器就知道你不當心寫錯了就能夠馬上報錯啦!!

 

4)可選變量# ---全部高級語言一開始就遇到的難題

好比客戶須要提供一個最終的API, 客戶給你一個數據源, 須要在數據源裏找到名字是「jack.xu」的學員成績。這個api的設計應該是這樣的:

C代碼 複製代碼  收藏代碼
  1. int FindScoreByName( DataSource*  source, string* name );  
int FindScoreByName( DataSource*  source, string* name );

 

問題來了,若是「jack.xu」的學員根本不存在,應該返回啥? 返回0?那確定不對,由於0有可能也是學員的成績。固然,若是返回的是類的對象,直接返回 NULL , 調用者就知道沒有找到,如今是基本數據類型,返回NULL 其實就是0,怎麼辦?(在C,C++中的規範作法是 返回bool表示是否找到,而成績經過形參來傳遞 ,其餘高級語言中能夠封裝一個小類/包裹類 )

 

Swift針對這個問題,專門設計了一個叫」optional value(可選變量)」  的變量,它就是爲了解決這個問題的。

語法:

C代碼 複製代碼  收藏代碼
  1. var n : UInt ? = 5    或者  var n ? = 5  
var n : UInt ? = 5    或者  var n ? = 5

 

這裏的?表示n 是個可選變量, 也就是說 n 有可能不存在, 什麼狀況下n不存在呢?

若是你這樣寫:

C代碼 複製代碼  收藏代碼
  1. var n : UInt ?  
var n : UInt ?

 

此外,須要注意的是swift語法中,nil 並非0 , 而是一個NilType類型的變量

因此上面提到的那個問題就能夠很容易解決了

C代碼 複製代碼  收藏代碼
  1. func FindScoreByName( source:DataSource, name:String )->UInt?  //返回的是可選變量  
  2. {  
  3.     var score : UInt ?; //此時 score 的變量沒有分配內存,也就是說score爲nil  
  4.     if( source.HasStudent( name: name ) )  
  5.         score = source[ name ]. score;  //這裏score才分配內存;  
  6.     return score; //若是沒有找到學生信息, score的內存一直沒被分配  
  7. }  
func FindScoreByName( source:DataSource, name:String )->UInt?  //返回的是可選變量
{
    var score : UInt ?; //此時 score 的變量沒有分配內存,也就是說score爲nil
    if( source.HasStudent( name: name ) )
        score = source[ name ]. score;  //這裏score才分配內存;
    return score; //若是沒有找到學生信息, score的內存一直沒被分配
}
相關文章
相關標籤/搜索