Load a UIView from nib in Swift
Tags: swift, ios
Published: 2020-06-14 07:31:03

การสร้าง custom view จาก XIB file น่าจะเป็นสิ่งที่เราชาว iOS น่าจะคุ้นเคยกันมา โดยส่วนตัวแล้วช่วงแรก ๆ ของการจะสร้างและใช้ XIB file คือ พังมาก 55555 ทำไมเรียกใช้ไม่ได้ฟะ ทำไมได้ nil ตลอด ดู tutorial จากหลาย ๆ ที่ก็ไม่ค่อยจะเหมือนกันอีก จากความเจ็บปวด และ ได้ลองผิดลองผิดมาเรื่อยจนเรียกได้ว่าโอเคในระดับที่ไม่ nil แย้วววว มาแบ่งปันกันครับ
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/yabbzlmu4yaqcxbsdgbx.jpg)

##1.สร้าง Xib File
สมมติว่าผมกำลังสร้าง custom view ที่เป็น Profile view ที่ประกอบไปด้วย Image view และก็ label ดังภาพด้านล่าง

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5zlfyo4tqjytb77sj603.png)

##2. สร้าง Swift File (Class)
โดยผมจะใช้ชื่อเดียวกับตัว Xib file เลย
```swift
//
//  ProfileView.swift
//
//  Created by sorawit on 13/6/2563 BE.
//  Copyright © 2563 sorawit. All rights reserved.
//

import UIKit

class ProfileView: BaseNibView {
    @IBOutlet weak var profileImageView: UIImageView!
    @IBOutlet weak var fullnameLabel: UILabel!
    
    func configure(with name: String) {
        fullnameLabel.text = name
    }
}
```

สังเกตว่า ProfileView ผมสืบทอดมาจาก BaseNibView เอ้ๆๆๆ มันคือ class อะไรทำไมไม่คุ้นเลย จริงๆ แล้วผมทำแยกออกมาอีกไฟล์นึงครับแบบด้านล่างนี้ เป็นเหมือนพิมพ์เขียวว่าเฮ้ย ถ้านายจะสร้าง custom view อะ นายต้องสืบทอดคุณสมบัติมาจาก Base ด้วยนะ จริงๆ เพื่อลดโค้ดใน custom view ในน้อยลง ปกติก็น้อยอยู่แล้ว 5555

```swift
import UIKit

public protocol UseNibView {
    var nibName: String { get }
}

extension UseNibView where Self: UIView {
    func registerNib() {
        if let view = Bundle(for: type(of: self)).loadNibNamed(nibName, owner: self, options: nil)?.first as? UIView {
            view.frame = bounds
            view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            addSubview(view)
        } else {
            fatalError("""
                Couldn't find Your Custom view for \(String(describing: self)),
                make sure the view is invalid nib name
                """)
        }
    }
}

open class BaseNibView: UIView, UseNibView {
    public var nibName: String { type(of: self).description().components(separatedBy: ".").last ?? "" }
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        registerNib()
    }
    
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        registerNib()
    }
}
```

##3. Connect Xib file with Class
หลังจากสร้าง Xib file และ ก็ Swift file แล้ว ขั้นตอนต่อไปก็คือการเชื่อมพลังกันของทั้งสองสิ่ง โดยไปที่ Xib file และเลือกไปที่ File’s Owner และ ก็ใส่ Class ให้ตรงกันกับที่เราสร้าง หลังจากนั้นก็ทำการลาก outlet ต่างๆ มา connect กันปกติ ถือเป็นอันเสร็จ

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pczmggu0p7dw0wgb6q2u.png)

##4. ไหนลองใช้งานหน่อยดีกว่า
แทแด่ ถือว่าใช้ได้

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kyiidm4szvinidhin3rs.png)

#** ข้อสังเกต ***
ตัว BaseNibView ใน function registerNib ผมมีการใช้ faltalError ไว้ในกรณีที่หาไฟล์ Xib ไม่เจอก็คือ ชื่อ Xib กับชื่อ Class ไม่ตรงกัน ดังนั้นถ้าเราทำทั้งสร้างไฟล์ที่มีชื่อไม่ตรงกันก็มีโอกาสที่แอป ฯ ของเราจะ force crash ได้เลย


###Reference:
https://stackoverflow.com/questions/24857986/load-a-uiview-from-nib-in-swift

###Source code:
https://github.com/sorawitt/Jibjib

จบไปแล้วสำหรับบทความเล็ก ๆ หากผิดพลาดประการใด ต้องขออภัยมา ณ ที่นี้ ยินดีรับแนะนำครับ ขอบคุณสำหรับการทนอ่าน 55555