筆者がいろんな言語を使用してきて、他の言語と異なる気になると感じたSwiftで押さえておきたい構文を「なにが出来るの?」といった視点で紹介していきます。

今回はExtensionについて公式サイトの説明を使用しながら解りやすく順に解説していきます。

 

 

Extensionとは?

Extension(拡張)機能は、既存のクラス、構造体、列挙型、プロトコル型に新しい機能を追加します。元のソースコードにアクセスできない型を拡張することもできます。

継承とは異なり新たなクラスを作成するのではなく既存のクラス、構造体、列挙型、プロトコル型に拡張して追加できるのが特徴!!

 

Extensionで”できる事”

  • 計算型プロパティを追加できる
  • 新しいイニシャライザを追加できる
  • インスタンスメソッドと型メソッドを追加できる
  • サブスクリプトを追加できる
  • 新しいネスト型を追加できる
  • 既存の型をプロトコルに準拠(追加できる

すごく簡単に要約すると”処理やプロパティを追加できる"ということです。

 

NOTE
拡張機能は新しい機能を追加することはできるけど、継承とは異なり既存の機能をオーバーライドすることはできません

 

Extensionの宣言

extension キーワードを使用して拡張機能を宣言します。

 

  extension OriginalTypeName{
    //  OriginalTypeNameに新しい機能を追加します。
  }

 

 

NOTE
拡張機能を定義して既存の型に新しい機能を追加すると、その型の既存のすべてのインスタンスで新しい機能を使用できる。拡張機能が定義される前に作成したインスタンスも含む

 

 

計算型プロパティを追加

計算型プロパティ

他のプロパティの値から都度計算または、処理して結果を返すインスタンスプロパティです。

 

extension String {
  var Mr: String { return "Mr." + self }
  var Ms: String { return "Ms." + self }
}

  let name = "jon".Mr
  print(name)
 // Mr.jon

 

 

新しいイニシャライザを追加

Float型に対応していないCGPointにFLoat型で入力できるようにイニシャライザを追加することができます。

 

extension CGPoint {
  init(x: Float, y: Float) {
    self.init(x: Double(x), y: Double(y))
  }
}

  let x = Float(3)
  let y = Float(5)
  let pnt = CGPoint(x: x, y: y)
  print(pnt)
  // 3.0, 5.0

 

インスタンスメソッドと型メソッドを追加

Extensionで追加したメソッドでもインスタンス自体の変更が可能

 

・インスタンスメソッドの追加

インスタンスメソッドとは通常のメソッド。

インタンス名.インスタンスメソッド名で使用する

インスタンス自身を変更する場合はmutatingを付加します。

 

extension String {
  mutating func prefixMr(){
    self = "Mr." + self
  }
  mutating func prefixMs(){
    self = "Ms." + self
  }
}
var name: String="Mark"
name.prefixMr()
print( name )
// Mr.Mark

 

  extension String{
    func repeatThreeTimes() {
      for _ in 0..<3{
        print(self)
      }
    }
  }

 

 

  let str: String = "good morning!"
  str.repeatThreeTimes{
    print(self)
  }

  実行結果
  // good morning!
  // good morning!
  // good morning!

 

 

・型メソッド

・既存の型に型メソッドの追加ができます。

 

extension Int{
   static func getOne(){
      return 1
   } 
} 

print(Int.getOne())
// 1

 

 

サブスクリプトを追加

Extensionにより、既存の型にsubscripts(添え字) を追加できます。

 

extension Int {
  subscript(index: Int) -> Int{
    var digit = 1
    while ((self / digit) != 0) {
      digit *= 10
    }
    var jyou = Int(pow(Double(10),Double( index + 1)))
    if digit < jyou {
      return 0
    }
    return (self / (digit / jyou)) % 10
  }
}

  let a = 12345
  
  a[0]
  // 1を返します。
  a[1]
  // 2を返します。
  a[2]
  // 3を返します。
  a[3]
  // 4を返します。
  a[4]
  // 5を返します。
  a[5]
  // 6を返します。
  a[6]
  // 7を返します。
  a[7]
  // 8を返します。
  a[8]

 

 

新しいネスト型を追加

既存のクラス、構造体、列挙型にネスト型を追加できます。

ネスト型・・・ クラス、構造体、列挙型の定義の中にさらに、クラスや構造体、列挙型を定義する事

 

  extension String {
    enum Kind {
      case mark,number,alphabet
    }
 
    var kind() -> Kind{
      let cstr:[CChar] = self.cString(using: .asci)!
      let code = Int(cstr[0])

      if 0x2f >= code {
        return .mark
      } else if 0x39 >= code {
        return .number
      } else {
        return .alphabet
      }
    }
  }

 

 

  func printAsciiKind(_ asciiStrs: [String]){
    for asciistr in asciiStrs {
      switch number.kind{
    	case .mark:
  	    print("mark ", terminator: "")
	    case .number:
	      print("number ", terminator: "")
	    case .alphabet:
	      print("alphabet ", terminator: "")
      }
    }
    print("")
  }

  printIntegerKind(["!","a","c","0","6"])
  // Prints "mark alphabet alphabet number number"

  

 

既存の型のプロトコルに準拠(追加)

拡張機能は、既存の型を拡張して、1つ以上のプロトコルを採用させることができます。プロトコルへの準拠を追加するには、クラスまたは構造体と同じ方法でプロトコル名を記述します。

 

  protocol TextRepresentable {
    var texturealDescription: String { get }
  }

  

 

  extension Dice: TextRepresentbable {
    // implementation of protocol lrequirements goes here
    var textualDescription: String{
      return "A \(sides)-sided dice"
    }
  }

   

 

参考文献:Swift公式日本語ドキュメント

 

おすすめの使用例

このExtension、既存のクラスにメソッドやメンバを追加できるので使い方を覚えるとかなりよいです。
例えば文字列の表示において一定の長さを超える場合3点リーダーで表示する箇所が多いアプリの場合

 

     今日は、良い天気だから...

  

次のようにStringにExtensionを使用して一定の長さを超える場合ある文字数に3点文字を付加するメソッドを追加することでどこからでも3点リーダー付の文字列に変換することができます。

 

extension String {
  func get3PointLeaderString(getCount: Int) -> String {
    if getCount < count {
      let str = prefix(getCount) + "..."
      return String(str) 
    }
    return self
  }
}

let sentence = "隣の客はよく柿くう客だ!!"
let read = sentence.get3PointLeaderString(getCount: 5)
print(read)
//  隣の客はよ...

 

 

 

最後に 

最後までお読みいただきありがとうございました。

今後も気になる構文を紹介していきたいと思いますので是非よろしくお願いいたします。ご意見などありましたらメッセージ頂けますと幸いです。

 

続いて「Delegate」について、以下のブログで紹介しています。よかったら参照してみてください。