2016年4月11日 星期一

swift 學習筆記 4: Class and Structure

Class       : 抽象化分類型別, 實體化後稱作分類體
Structure : 抽象化結構型別, 實體化後稱作結構體

分類(class)及結構體(structure) 是程式建構中一般常用且很彈性的結構區塊,  裏面定義了屬性(property)及方法(method)用來運作分類及結構體的功能, 對於常數(constant),變數(variable)及程序(function) 它們都同樣使用相同的語法

不像其它程式語言, swift 並不需要將自訂的分類及結構分離成介面(interface)與實現(implementation)兩個檔案, 而是將分類及結構體定義在一個檔案裡, 其他程式便可以用其外部介面直接使用

分類的實體(instance)傳統上認知它就是一個物件. 但在 swift 裏面, 它更像是其他程式語言裡的程序, 本章大多數所敘述的程序都可以指定給實體, 因此 instance 被當成作是更廣泛的用語

分類與結構體的比較
相同點:
1. 定義屬性來保存數值(value)
2. 定義方法提供運作
3. 定義下標索引(subscript)方法,透過下標語法來取用內部數值
4. 定義起始程序設定初始狀態
5. 可以被擴展(extended)將預設的運用加以擴充
6. 可以與協定搭配來提供特定功能的標準運作

分類另外有著與結構體所不同的能力:
1. 分類可以繼承其它分類的特性
2. 型別標示(type casting)讓運行時可以檢視及解釋物件(class instance)的型別
3. 消滅程序(deinitalizer)讓物件可以釋放它所指定的資源
4. 參考計數(Reference counting)允許超過一個以上的物件來引用

宣告的語法
分類及結構體有相同的語法來宣告, 分別採是用關鍵字  class 及 structure , 且整個定義內容都是放在大括號 {} 裡頭, 例如

struct MystructDefinition {
// define propertys and methods
var width=0;
}

class   MyclassDefinition {
// define propertys and methods
var st =MystructDefinition()
var name:String?
}

let myInstance=MyclassDefinition()
let myInstance.name="A new instance"

當定義了一個分類及結構體後, 實際上是定義了一個全新的型別, 標準的 swift 型別名稱是將首字頭大寫相連接(NewClassName), 而屬性及方法的名稱則是用第一個字小寫(myPropertyOrMethod)命名,有別於型別名稱作區分, 可以參考上述的內容.

其中 MystructDefinition() 會將新的結構體實體化, 而 name 賦予了一個字串型別的 nil (表示空字串), 他是一個可無(optinonal)宣告
而 MyclassDefinition() 則是將分類允以實體化成物件, 如要取用物件屬性或方法等成員時, 使用句點語法 '.' 直接取用, 參考下面範例:

Class MyNewClass{
var name:String?
}
let a=MyNewClass()          // a is a constant of  new Class, so it can't be assignd in the next time.
let c=MyNewClass()          //  c is different from with a
a.name="My Name"         // but a.name is a variable defined in the class.
//  a class instance is a reference type, even if it is a constant reference, it's property can also be assigned a new value.
// but a structure instance is a value type, if it is a constant value, it's propety can't be assigned even if it was declared as var in structure.
c.name="Youe Name"     //  c also has a name property
let b=a                                    //  b refer to the same class as a
b.name="New Name"       //  a.name will be modified,too. but c.name doesn't

在上述例子中,新分類後面接了小括號(),就是將class實體化成一個新instance,該instance稱做class instance.
如果新結構後面接了小括號(),也是將struct實體化成一個新instance,該instance稱做structure instance.

所有 swift 的基本型別像是整數, 浮點數, 邏輯, 字串, 陣列, 字典等型別都是數值型別(value types), 它們是以結構體在幕後實現的.

在 swift 裡面,所有結構體及列舉體也都是數值型別, 這意味著當這些結構體及列舉體被傳遞(指定)時,將會整個複製過去,因此他並不會影響到別的實體

但分類體卻是一個參考型別(reference type),因此當結構體被實體化後,指定給一個常數或變數時,它其實是指向該分類體. 所有的參考到該分類體的instance都可以改變其內容, 且改的都是同一個實體

因此將 class instance 指定給一個新變數, 除非是實體化成一個新的分類體(如上述的 c), 否則只是將指標傳遞過去而已(如上述 let b=a), 並非將整個分類體複製過去

因於分類是屬於參照型別(reference type), 有別於數值型別(value type), 有可能在幕後好幾個常數或變數參考到相同的分類體(有別於結構體與列舉體,他們是將整個物件複製過去), 有時候要找出兩個常數或變數是否確實參考到相同的實體,可以透過用等效運算子( ===  或  !== )來檢視, 須注意的是, 等效並不是相等的意思,  等效運算指的是有無參照到相同的分類體


定義客制資料型態可以採用分類或結構當成是程式碼的架構區塊, 然而結構體總是傳值,而分類體總是傳參,這意味著他們適合不同的工作,對於要決定一個專案的資料結構及功能,需要考慮的是到底分類體好還是結構體好,底下有一些準則可以考慮使用結構
1.結構主要功用是將相當少量及簡單的資料數值加以打包
2.可以合理的預期打包的數值將會被複製而不是去參照
3.由結構體所儲存的任何屬性,他們本身是數值型別,同時預期這些東西將會被複製而不是去參照
4. 結構體不需要繼承別的已存在類型的屬性或行為

一些候選使用結構體的例子包括
1. 幾合型態的尺寸,譬如長寬都用精密(Double)型別
 2. 一系列範圍參考方式,譬如起點及長度都用整數(Int)型別
 3. 三維座標系統的點, 譬如x,y,z 屬性都用精密(Double)型別

在 swiftt 裡, 基本資料型別像 Sting, Array, Dictionary 是使用結構體來實現,這意味著當它被賦予後指定給一個新常數或變數時,將會被整個複製過去, 或者當他們傳給程序(function)或方法(method)時也是如此(實際上, swift 在幕後, 只有當需要複製時才會執行搬運的動作. 他會處理所有數值的複製工作.以保證效能最佳化,你並不應該為了搶佔效能而去避免指定工作)
但在 Foundation 裡 NSString, NSArray, NSDitionary 是用分類而非結構來實現的, 與上述行為並不相同, 因此再 Foundation 裡的字串,陣列,及字典等總是將已存在本尊的指標傳過去,而非將本尊整個複製過去



解決 geany 無法使用 gcin 的問題

在 linux mint 上已經裝了 gcin, geany, 但發現在 geany 無法使用 gcin, 他真正的問題是因為快捷鍵 ctrl-space 相衝, 解決的辦法是將它改掉就可以了.

1. 將主選單的  求助(H) -> 快速鍵(K) 叫出來, 往下拉到編輯器,再往下找有個項目 "補完字詞" 所設定的按鍵, 他正好是 Ctrl+Space, 點選 Edit 按鈕

2. 接著會跳出快速鍵變更的選單, 往下拉到編輯器,再往下找有個項目 "補完字詞" 已經反白, 直接點下去再按 變更(H) 按鈕

3. 接著它會跳出視窗訊息, 跟著訊息做, 直接敲下別的組合鍵,讓他不再是 Ctrl-Space 就好. 當然也不要跟別的功能鍵互相衝突, 敲完組合鍵, 他會顯示你所敲的組合鍵,確認後再按 OK 按鈕,變更設定完成

4. 關掉重新打開 geany, 應該就可用 gcin 來切換輸入法了 


swift 學習筆記 3: Dictionary

字典型別是用成對 key:value 元素所組成的集合, 各元素以逗點分開, 使用 [:,:,...] 組成集合, 它其實也沒有順序可言, 但很重要的特性是 key 的值絕對不能有重複, 字典的型別宣告使用Dictionary<TYPE of key:TYPE of value> 來敘述, 簡單的也可用 [TYPE of key:TYPE of value] 來敘述, 例如:
let mydic:[Int:String]=[3:"a",2:"b",1:"CC"]

當然 swift 也可自動推斷出上述的型別, 因此 TYPE 其實也可以省略不寫,下面字典宣告也是符合語法的
var vardic=[2:"a",1:"b",3:"CC"]

字典型別可以透過 key 當索引值, 直接取用 value, 例如
vardic[1]="SDSD"  // 直接更改 key=1 的值, 現在 vardic 將變成是  [2:"a",1:"SDSD",3:"CC"]

如果要清空字典. 可用 [:] 來直接賦予便可, 前提當然該 instance 必須之前就已宣告成變數
var dic=[2:"DD",4:"ww",5:"DDD"] // 宣告字典變數並實體化 instance
dic=[:] // 清空字典內容

透過 key 來取用字典內其所對應的值(value)時, 有可能該 key 並不存在, 因此可運用 optional binding (if let) 來運作較保險


如果要刪除字典內的成員(成對元素), 可以透過將 nil 值賦予字典 key 所對應的成員, 例如
vardic[3]=nil   // 刪除 key=3 的成員


如要列出字典內所有 key, 可以用 for-in 迴圈搭配字典的 .keys 來一一列出, 例如
var vardic=[2:"a",1:"b",3:"CC"]
for i in vardic.keys {
   print("Key:\(i)")
}

如要列出字典內所有 value, 可以用 for-in 迴圈搭配字典的 .values 來一一列出, 例如
var vardic=[2:"a",1:"b",3:"CC"]
for i in vardic.values {
   print("Value:\(i)")
}


字典的屬性及工具:
isEmpty: 驗證是否是空字典
updateValue(,forkey:)
removeValueForKey()



swift 學習筆記 2: Set

集合(Set)型別適合用在秩序並不是很重要的搜集(collection)上, 它最重要的特性是其成員都是唯一, 並不會重複, 如有重複的值, 將會被自動剔除掉只剩一個. Character,  String, Int, Double, and Bool等型態的元素等都可當作集合內的元素(value), 由於 Set 無簡單的宣告形式, 只能用 :Set<TYPE>的方式來宣告集合的類型. 例如字串的集合:
let myset:Set<String> =["a", "bb", "ccc"]

集合不同於 Array, 他並沒有順序, 但可以利用 sort() 來排序. 降羃排序用 sort(>) , 升羃排序(預設由小到大排序)用 sort(<) 因此 sort()等同於 sort(<)例如:
myset.sort(>)

Set 重要的工具(method)及屬性(property):
count : 計錄內部成員個數
isEmpty: 當集合內無成員時,其值為 true
insert() : 插入新成員, 如新成員已存在, 將會忽略此運作
remove(): 移除舊成員, 避免成員不存在可以使用 optional binding ( if let ) 來運作.
contains(): 檢視成員是否存在

集合的算術運算:
intersect(): 兩者交集後產生新集合
union(): 聯集後產生新集合
exclusiveOr(): 聯集並移除兩者的交集後產生新集合
subtract(): 相減後產生新集合

集合的邏輯運算
== : 比較兩個集合是否相同
isSubsetOf(): 判斷是否是括符內集合的子集合
isSupersetOf(): 判斷是否是括符內集合的父集合
isStrictSubsetOf()
isDisjointWith()


var c:Set<Int>=[1,6,5,6,1,6,6,7]    // in fact, c will be {5,6,7,1}
if let c.remove(9) {
      printf("Found and remove it")
} else {
      printf("Member is not exist")
}

c.insert(8) // c will be {5,6,7,1,8 }








2016年4月10日 星期日

swift 學習筆記 1: enum

enum 是用來自訂"列舉型別", 列舉成員屬性用 case 來宣告. 如下所述:

enum Myenum {
case head, body, leg, hand
}

宣告變數隸屬 Mynum 型別, 初始值為 head:
var a: Myenum = Myenum.head

上述型別(:Myenum)其實 swift 可以推論出來, 可以不寫, 同樣合語法.
var a=Myenum.head
// 一旦 type 確認後, 修改值直接用具句號取值就可
a=.body

變數 a 經上述型別設定後, 則只能賦予 Myenum.head Myenum.body, Myenum.leg, Myenum.hand 等四種值. 而將變數 a 列印出來會發現, 它只可能是集合 { head, body, leg, hand } 中的成員之一.

利用協議(protocol) 來定義自體特異功能 (Mutating Method)

protocol Myprotocol {
mutating func toggle()
}

也些時候 instance (實體, 實例, ...?) 的自體內容需要被改變, 它可透過自我 method (方法, 工具, 功能, 運功, 特異功能 ...?) 來改變. 如要強制用此種方式修改就稱作協定, 而型別如果運用(遵循)此協議的必須將它實現, 由於它可能會動用到自體內容, 因此該 method 必須加上 mutating 的前置字眼

底下定義了一個列舉型別 Myswitch{Off, On}, 須遵循 Myprotocol, Myprotocol 裏面只有一個用來切換 (toggle) 的功能需要被實現, 而該切換的動作會改變到本身(instance self), 故此方法必須標明是 mutating, 否則 compile 會報出錯誤訊息

  1. enum Myswitch: Myprotocol {
  2. case Off, On
  3. mutating func toggle() {
  4. switch self {
  5. case Off:
  6. self = On
  7. case On:
  8. self = Off
  9. }
  10. }
  11. }
  12. var sw=Myswitch.On         // instantiate sw 被實體法, 它隸屬 Myswich 型別
  13. print("Now sw state is:\(sw)") // sw=On
  1. sw.toggle() // 使用特異功能來切換 sw 的值
  2. print("Now sw state is:\(sw)") // sw=Off
  3. // mutating func --> 我把它翻譯成特異功能, 因為它會改變 self.







2016年4月9日 星期六

玩玩 swift

swift 是開發 iOS 程式重要的語言工具之一, 目前是 open source,

官方網站:  https://swift.org/

首先在 linux 下需架好環境:

參考網址
https://swift.org/getting-started/#installing-swift
https://linuxmint.tumblr.com/post/135280204927/how-to-use-swift-programming-language-in-ubuntu


1.  swift 官方下載: https://swift.org/download/#releases
    https://swift.org/builds/development/ubuntu1510/swift-DEVELOPMENT-SNAPSHOT-2016-01-25-a/swift-DEVELOPMENT-SNAPSHOT-2016-01-25-a-ubuntu15.10.tar.gz.sig
https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-01-25-a/swift-DEVELOPMENT-SNAPSHOT-2016-01-25-a-ubuntu14.04.tar.gz
     p.s. 因 release 版未將 swift-build 放入, 最好下載上述開發版
2. 使用 tar 解出swift 套件:  tar -zxvf  xxxx-xxx.xz
3. 設定好環境變數 PATH 指向swift 編譯程式的 bin 目錄: export PATH= ....:$PATH
4. 安裝開發 swift 所需要的相關套件:   apt-get install clang   libicu-dev
5. 驗證是否安裝成功:  swift -version
6. swift 交談命令程式(REPL), 直接執行 swift 就可看到:  swift
     在 REPL 中鍵入 :q 離開 swift 交談視窗
7. 建立編譯環境
     a. 建立一個目錄當專案:  mkdir Hello
     b. 進入該專案目錄:  cd Hello
     c. 建立 Package.swift 檔案: touch Package.swift
     d. 建立原始碼目錄: mkdir Sources
     e. 建立原始碼主檔: touch Sources/main.swift
     f. 編輯主檔: gedit Source/main.swift
         將程式碼 print("Hello World") 鍵入主檔(main.swift)中
     g. 開始編譯: swift build

         編譯程式將 Source/main.swift 加以編譯程可執行檔,使用 Package.swift 所在的目錄名稱來命名可執行檔, 編譯好的執行檔將會放在 .build/debug 目錄內

     h. 執行編譯過的程式:      .build/debug/Hello

基礎知識:
常數宣告 let  a=...
變數宣告 var a=...

常數型別(TYPE)宣告   let a:TYPE=...
變數型別(TYPE)宣告  var a:TYPE=...
其中 TYPE 可以是: Int, Uint, Float, Double, String
(整數, 浮點數, 更精密浮點數, 字串)

許多型別, 其實swift 會自行推論出正確的型別,
例如 var a=1   ---> a 是整數
         var b="sasds"  --->  b 是字串
         var c=1.23       --->  c 是 Double
...等等, 因此上述的 a,b,c 其實不需宣告型別(TYPE) 也可以


何謂 Tuples: 將各種型別組合成一個集合, 例如 let a=("1",2,3.1415)
其中 a.0 等於字串 "1", a.1  等於整數 2, a.2 等於浮點數 3.1415
將Tuple 值用括號可以分離出各元素:
例如  let a=("1",2,3.1415);  let  (a0,_,a2)=a , 其中 a0="1", 第二個使用底線忽略, a2=3.1415

陣列型別使用相同型別的元素用 [,,] 來構成, 例如 let a=[1,2,3]
字典型別用key:value成對元素陣列所構成 let dic=["a":"dsd","2":"kiki"]; let b=dic["a"];
其中 key 與 value 型別必須分別統一使用相同型別  let dic=[1:"dsd",2:"kiki"]; let b=dic[1];

何謂 optionals (可有可無)變數, 例如宣告 var a:Int? =404, 其中後面 '?' 就已代表 a 宣告成可有可無的整數型別, 可有可無意味著:變數未指定也可, 此例 a=nil, 或已指定完, 此例 a=404
但不指定 optionals 的變數, 則不能付與 nil 值

當一個可有可無變數要強制取用其值時,可以再後面加上驚嘆號 '!',強制取用,但一旦此變數若未指定.則程式可能會當掉
因此可以透過 optional binding 敘述來檢查 , 避免錯誤
if let  constantname = someOptionalvalue {
//   ...
}

錯誤處理程式
func catThrowAnError() throws {
 // ..程式可能會丟出依些錯誤訊息
}


do {
          try catThrowAnError()
       
          // ... No error, continue
     }   catch  Error1.xxx {        
          // ...
     } catch  Error2.xxx {        
          // ...
      }
自訂驗證程序宣告, 當 condition 有錯誤時, 則停止程式, 並丟出錯誤訊息:
   assert(condition,"Error message");

字串可以相加  "Hello" + "World"
餘數  (a%b)
範圍 1...5     指的是 1 到 5
範圍 0..<10 指的是 0 到 9 ( 從0 開始, 小於 10)

the nil coalescing operator ??
let a:Int?=nil      // define an optional Interger constant, assign it to nil
// if a is not nil return a , else return 0
let b= ( a != nil ?  a!: 0 )
// same as expression    a ?? 0
let b=( a ?? 0 )

Type casting: 成型

字串的method
1. characters.count
2. append
3. insert

var a="SDSD"
a.characters.map {$0} // list all the character

單一字元(single character)並不等於單一字元的字串(a string with single character), 在於它是不同型別, 字元用 Character 來宣告, 字串用 String 來宣告, 使用前後雙引號時將自動判斷為字串型別

swift 語言有3種主要的收集型別(collection type): 陣列(Array),  集合(Set), 字典(Dictionary, 這些行別都是 mutable, 可修改的. 但若宣告程常數就不得修改了

在 swift 裡的條列式流程 switch .. case, 在case 執行完後將會自動跳離, 不像 c 語言要加入 bread 來跳開. 但可以用 fallthrough 讓它往下繼續執行, switch 可以用 tuple 當成多變數條件式, 如果無關係的條件, 可以用底線 '_' 讓它忽略該條件

switch (a,b) {
    case (_,0) :
                      ...
    case (0,_) :
                       ...
    default:
                       ...
}

value binding: 數值綁定
在switch-case 的條件式裡可以用 let 語法來綁定數值(value binding)讓他可以在該條件成立下取用,例如:
var a=(2,3)
// ...
 switch  a {
   case (let b,_) :
       print("\(b)")
   case (_,let c) :
       print("\(c)")
   default:
      print("OK")
 }

label: 標籤可以用名稱加帽號 lableName: 加註在程式迴圈上, 之後用 break lableName, 或 continue lableName 來控制程式流程, break lableName 用來結束迴圈內程序而跳到所標註迴圈外再往下執行. 而 continue lableName 除了放棄迴圈程序外, 並重新跳到所標註迴圈開頭地方再執行

guard  指令類似 if 的語法, 但 guide 必須要有 else 指令附加在後面, 而且他通常是用在func裏面,最後要有 return, 它預期條件式是對的,一旦不對才執行後面 else 內的指令,可以減少在對的條件成立時再寫指令
func my(b:Int) ->  {
     guard  b>3 else { print("OK"); return; }  
}
my(4)  // OK
my(3)  //

初始化消滅:當抽象型別像分類(class),結構(struc)及列舉(enum)要實體化成個體時, 他會執行該型別的的初始化程序叫 init(). 只有分類所產生的個體, 當要消滅時才會執行消滅程序叫作 deinit(), 對於儲存式屬性, 可以在型別宣告時就直接給初始值, 也可以透過初始化參數設定該屬性.初始化參數的語法與 func 裏面的參數語法是相同的. 對於常數型態的屬性仍然可以透過上述初始化程序重新設定它, 之後常數就不得再更改了. 對於分類所產生的個體而言, 常數屬性不能被子類別的繼承者所修改









改用 Tor browser 匿名瀏覽, 真正隱私不被追蹤的瀏覽器

只要身處在網際網路的世界, 其實行蹤早已暴露, 只要有心人士要追蹤,其實是逃不掉的,最近看到一個瀏覽器宣稱可以防止這樣的事情,當用的人愈多,其實行蹤愈安全,他的封包是透過
Tor節點來加密保護, 算是相當安全的連線. 可有效防止像 "traffic analysis" 分析軟體解析出瀏覽者的網路使用行為
參考 Tor 的官方文章: https://www.torproject.org/about/overview.html.en
他闡述了 Tor 的運作方式,且它本身是一個 open source, 由一群自願者所開發,值得推荐使用
官方下載區:
https://www.torproject.org/projects/torbrowser.html.en#linux