Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
OrganizationAdvent CalendarQiitadon (β)
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

名前付き UIView と後付けストアドプロパティもどき

More than 1 year has passed since last update.

名前付き UIView

Storyboard などで配置した UIView に @IBOutlet を使わないでアクセスしたいとします。なぜ、@ IBOutlet を使わないかは大人の事情で割愛するとして、そうした事情でコードなどで特定の UIView をアクセスしたい場合に、Storyboard で配置した UIView やそのサブクラスに、tag に数字を仕込み、 viewWithTag() で 特定のViewにアクセスする事ができます。

// An integer that you can use to identify view objects in your application.
var tag: Int

// Returns the view whose tag matches the specified value.
func viewWithTag(Int) -> UIView?

最近、またこの大人の事情で、@IBOutlet を使わないで、特定のViewにアクセスする必要が出てきました。以前と同様tagを使ってもいいのですが、時代的には String を使いたいと思いました。そこで、Storyboard の User Runtime Attribute を利用して、名前 name でアクセスできるような extension を書いたので紹介いたします。

import UIKit

fileprivate var viewNameMap = NSMapTable<UIView, NSString>.weakToStrongObjects()

extension UIView {

    @IBInspectable dynamic public var name: String? {
        get {
            return viewNameMap.object(forKey: self) as String?
        set {
            if let name = newValue {
                viewNameMap.setObject(name as NSString, forKey: self)
            else {
                viewNameMap.removeObject(forKey: self)

    public func view(named name: String) -> UIView? {
        if self.name == name {
            return self
        for subview in self.subviews {
            if let view = subview.view(named: name) {
                return view
        return nil

実は全ての UIView に name プロパティを用意しているわけではなく、name にwriteアクセスがあった場合に同UIViewとその名前の関係を記憶します。そして、同 View がリリースされる時に、nameもリリースされます。仕組みは、NSMapTable.weakToStrongObjectsを利用してます。

使い方は、先のコードをプロジェクトに組み込んだ状態で、Storyboard から目的の View に名前をつけます。「Identity Inspector」からでも結構ですし、「Attributes Inspector」経由でも結構です。

クライアント側のコードはこんな感じです。.view(named:) でアクセス可能です。目的のUIView のサブクラス特有のメソッドやプロパティにアクセスする場合は適切にキャストしてあげる必要があります。

class ViewController: UIViewController {
    // ...
    override func viewDidLoad() {
        let cyanView = self.view.view(named: "cyan")
        let magentaView = self.view.view(named: "magenta")
        let yellowView = self.view.view(named: "yellow")
        cyanView?.backgroundColor = UIColor.cyan
        magentaView?.backgroundColor = UIColor.magenta
        yellowView?.backgroundColor = UIColor.yellow


応用すれば、自分で好きなストアドプロパティもどきを好きな View に追加可能です。試しに、dictionary プロパティを追加できる extension を用意してみましょう。

import UIKit

fileprivate var viewDictionaryMap = NSMapTable<UIView, NSDictionary>.weakToStrongObjects()

extension UIView {
    public var configuration: NSDictionary? {
        get {
            return viewDictionaryMap.object(forKey: self)
        set {
            if let newValue = newValue {
                viewDictionaryMap.setObject(newValue, forKey: self)
            else {
                viewDictionaryMap.removeObject(forKey: self)

これは、User Runtime Attribute で Dictionary を指定できないので、Storyboard 自体に情報を仕込む事はできませんが、コードで特定の view に NSDictionary を set/get できるようになります。




まぁ、小ネタなので、必要ないかもしれませんが、参考までに Git にサンプルを用意いたしました。




Xcode Version 11.3 (11C29)
$ swift --version
Apple Swift version 5.1.3 (swiftlang-1100.0.282.1 clang-1100.0.33.15)
Target: x86_64-apple-darwin19.0.0
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away