LoginSignup
7
2

More than 3 years have passed since last update.

SwiftのExtensionをより分かりやすく -TargetedExtension-

Last updated at Posted at 2019-12-12

はじめに

本記事はCyberAgent 20新卒 Advent Calendar 2019の13日目の記事です!
もうすこしでクリスマスですね🎅🎄

// TODO: 追記します!
- 昨日の投稿は, Ayumuくんの「Lottieを使ったAndroidのアニメーション実装」でした!
- そして, 14日目の投稿はdragon_taroくんの「」です!
ぜひこちらもご覧ください!!

本日(アドベントカレンダー13日目)の記事は, よだだよ!or ヨーダが担当します!
普段から触っている技術はiOSで, 最近は研究や受託開発等でARKitを使うことが多いです.

しかし,
今回はSwiftExtensionの記事を書こうと思います!

※実は, 「ARKitを使って, クリスマスぽいお絵かきARアプリを作ってみよう!🎄🎨」というタイトルで書こうと思ってましたが, 間に合わなそうなのでテーマを急遽変更しました!
時間のあるときにでも, お絵かきAR作ってみる記事は書こうと思います.

SwiftのExtensionとは...

  1. クラスや構造体, 列挙体の拡張
  2. プロトコル拡張(デフォルト実装)
  3. クラスや構造体, 列挙体をプロトコルに適合させる
Extension+String.swift
extension String {
  // 追加するメソッド等
  func printHoge() {
    print("hoge")
  }
}

// 呼び出し
String().printHoge()

↑例えばこのように拡張することはあるかと思いますが,
もとからあるのもなのか, それとも拡張され追加されたものなのかを判別するのは分からないと言う問題があります.

そこで, 拡張され追加されたものには, プレフィックスを付けます.
そのようにすることによって, 拡張されたものであることが明示的になると同時に, プロパティの衝突も避けることができます.

では, ここから実際にTargetedExtensionを実装していきます!

Extensions実装

今回は例として, FileManagerを拡張してみたいと思います!
ちなみに, このメソッドは指定パスにあるファイルを一覧を表示するものです.

下のものは, 単純にFileManagerを拡張したものになります.

FileManager+Extensions.swift
import Foundation

public extension FileManager {
    /// List local files (specified path)
    func listupLocalFiles(path: String) {
        do {
            // Get all file name strings in path
            let files = try FileManager().contentsOfDirectory(atPath: path)
            // Get file name as String array
            print(files)
        }
        catch let error {
            // Error : If path doesn't exist
            print(error)
        }
    }
}

// Usage: Temp Directory
let fm = FileManager()
fm.listupLocalFiles(path: NSTemporaryDirectory())

普通に拡張すると, fm.listupLocalFiles(path: NSTemporaryDirectory())になり,
最初に挙げたように, 元からあるものなのか, 追加されたものなのかが分かりません.

Targeted Extensionsで実装

FileManager+Extensions.swift
import Foundation

public protocol FileManagerComapatible {
    associatedtype CompatibleType

    var ex: CompatibleType { get }
}

public final class FileManagerExtension<Base> {
    private let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

public extension FileManagerComapatible {
    var ex: FileManagerExtension<Self> {
        return FileManagerExtension(self)
    }
}

extension FileManager: FileManagerComapatible { }

extension FileManagerExtension where Base == FileManager {
    /// ローカルファイル(指定パス)のリストアップ
    func listupLocalFiles(path: String) {
        do {
            // Get all file name strings in path
            let files = try FileManager().contentsOfDirectory(atPath: path)
            // Get file name as String array
            print(files)
        }
        catch let error {
            // Error : If path doesn't exist
            print(error)
        }
    }
}

// Usage:
// let fm = FileManager()
// fm.ex.listupLocalFiles(path: NSTemporaryDirectory())

TargetedExtension呼ばれる形で実装することで,fm.ex.listupLocalFiles(path: NSTemporaryDirectory())といった形にすることができます.

メソッドの前に, exを挟むことで, 「これは追加されたもの」なんだと理解することができます!

// TODO: コードの説明の追加

まとめ

  • TargetedExtension呼ばれるにすることで, Extensionであることが明示的になる
  • また, 名前の衝突も避けることができるというメリットが生まれます.

※後で, #TargetedExtension部分は, コードの説明を交えて丁寧なものにしたいと思います.

参考

告知

今年もサイバーエージェントの本選考がやってきたみたいです!
興味ある方は, 以下のURLからチェックしてみてください!!
https://www.cyberagent.co.jp/careers/special/engineer2021/

  • 早期選考で内定となった場合, 長期実務インターンをすることができます!
  • #cypitch をつけてTwitterに呟くと, それが会社説明資料になるみたいです!

僕自身がCyberAgentを選んだ理由はたくさんありますが,
その1つとして「人の良さ」です!!
「人の良さ」ってのを言葉で正確に伝えるのは難しいので, Zehi社員さんに会ってみてください!(勿論, 内定者でも大丈夫です!)
きっとこの言葉の意味が感じられるような気がします!

最後まで読んでくださり, ありがとうございました🙇‍♂️

7
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
2