Author: DaoNM2

  • Apple Developer Account: Sự khác nhau giữa tài khoản developer thông thường và tài khoản doanh nghiệp

    Apple Developer Account: Sự khác nhau giữa tài khoản developer thông thường và tài khoản doanh nghiệp

    Bạn là một nhà phát triển ứng dụng của Apple, bạn muốn ứng dụng mình phát triển được bày ở trên cửa hàng ứng dụng (App Store) của Apple, hay bạn muốn phát triển một ứng dụng nội bộ chỉ dành riêng cho nhân viên trong công ty, tổ chức của bạn. Để thực hiện được việc này bạn cần phải có một tài khoản nhà phát triển của Apple cung cấp. Tuy nhiên mỗi một loại tài khoản lại có một mục đích khác nhau. Nếu bạn đang băn khoăn về việc chọn tài khoản nào phù hợp với trường hợp của mình thì ở bài viết này mình sẽ giải đáp thắc mắc đó.

    Có những loại tài khoản nào?

    Apple cung cấp hai loại tài khoản: Apple Developer ProgramApple Developer Enterprise Program. Vậy chúng ta nên chọn tài khoản nào cho ứng dụng của mình?

    Apple Developer Program

    Tài khoản này dành cho các nhà phát triển hoặc công ty muốn cho phép phân phối qua App Store cho bất kỳ ai. Các bản dựng được phát hành trong quá trình phát triển vẫn được cài đặt qua App Center.

    Ưu điểm

    • Giá rẻ nhất $99 một năm
    • Có thể đẩy ứng dụng lên cửa hàng ứng dụng của Apple cho tất cả mọi người tiếp cận và tải xuống
    • Bạn có thể thực hiện build/test trên 100 thiết bị khác nhau, điều này khá là tiện lợi cho việc phát triển ứng dụng của bạn
    • Ứng dụng của bạn có thể tìm kiếm được bằng các công cụ tìm kiếm khác nhau như Google, Bing …

    Nhược điểm

    • Trong quá trình phát triển các thiết bị được phép bị giới hạn ở 100 thiết bị, các thiết bị này cần phải đăng ký trước khi cài đặt các bản buil.
    • Do nó được công khai cho tất cả mọi người có thể tải xuống và sử dụng, nên nó sẽ không phù hợp với các ứng dụng nội bộ chỉ dành riêng cho nhân viên
    • Ứng dụng của bạn phải đảm bảo các yêu cầu khắt khe của Apple
    • In-app purchase bắt buộc phải qua Apple Payment center, Apple sẽ thu 30% phí.

    Chọn loại tài khoản này nếu bạn có ý định đưa ứng dụng của mình lên cửa hàng ứng dụng của Apple để tất cả mọi người có thể tiếp cận và tải xuống app của bạn.

    Bạn có thể xem thêm thông tin về chương trình tài khoản này ở đây

    Apple Developer Enterprise Program

    Đây là loại tài khoản cho phép các tổ chức lớn phát triển và triển khai các ứng dụng độc quyền, sử dụng nội bộ cho nhân viên của họ. Chương trình này dành cho các trường hợp sử dụng cụ thể yêu cầu phân phối riêng tư trực tiếp cho nhân viên sử dụng hệ thống nội bộ an toàn hoặc thông qua giải pháp Quản lý thiết bị di động.

    Ưu điểm

    • Không bị giới hạn số lượng thiết bị cài đặt
    • Các thiết bị không cần đăng ký trước để có thể cài đặt ứng dụng
    • Ứng dụng của bạn không cần phải tuân theo các quy tắc của Apple và không bị Apple review.
    • Vì ứng dụng không cần thiết lập trong cửa hàng ứng dụng Apple nên bạn không cần điền mô tả ứng dụng đầy đủ, tạo hình ảnh để quảng cáo ứng dụng hoặc tạo chính sách bảo mật công khai, v.v.
    • In-App purchases không cần thiết phải qua Apple Payment center vì vậy không phải chịu phí của Apple
    • Ứng dụng của bạn sẽ không bị các bên khác tìm kiếm được thông qua các công cụ tìm kiếm, vì vậy nó bảo mật hơn

    Nhược điểm

    • Người dùng sẽ phải cài lại ứng dụng hàng năm trước khi hồ sơ bị hết hạn, trừ phi bạn sử dụng giải pháp MDM(Mobile Devices Manager)
    • Việc cài đặt ứng dụng phức tạp hơn vì người dùng phải cài đặt, tin cậy nhà phát triển thay vì tự động như khi tải trên App Store
    • Giá cao nhất $299 một năm

    Bạn nên chọn loại tài khoản này nếu bạn cần phát triển các ứng dụng nội bộ, độc quyền dành riêng cho nhân viên trong công ty, tổ chức mà không muốn đẩy ứng dụng lên cửa hàng ứng dụng của Apple.

    Bạn có thể xem thêm thông tin về chương trình tài khoản này ở đây

  • Unit Test – How to unwrap optional value in XCTest

    Unit Test – How to unwrap optional value in XCTest

    Trước khi Xcode 11 ra mắt, để unwrap một optional value chúng ta vẫn thường phải dùng Guard/if let, điều này khá bất tiện trong khi viết Unit test. Khi viết test case chúng ta không nên đưa các câu lệnh điều kiện vào trong các func test vì nó sẽ tạo ra một logic mới trong Unit Test nó khiến test case của chúng ta rắc rối và phức tạp.

    Để các bạn dễ hình dung hơn, mình có tạo một Struct Person có thuộc tính address là optional (có thể nil) như dưới đây:

    struct Person {
        let name: String
        let address: String?
    }

    Thông thường chúng ta sẽ thực hiện unwrap như sau:

    func test_Address_caseNil() throws {
        let personModel: Person = Person(name: "John", address: nil)
        // unwrap optional value 
        guard let address = personModel.address else {
            XCTFail("Expected non-nil address")// throw fail
            return
        }
        
        XCTAssertEqual(address, "Hanoi")
    }

    Trong trường hợp này địa chỉ đang nil nên test case này sẽ bị lỗi và throw thông báo “Expected non-nil address”

    Có một cách thông dụng hơn là không unwrap mà sử dụng trực tiếp giá trị optional để verify test case như sau:

    func test_address_caseNil() throws {
        let personModel: Person = Person(name: "John", address: nil)
        
        XCTAssertEqual(personModel.address, "Hanoi")
    }

    Khi chạy test case này ta nhận được thông báo lỗi như sau:

    test_address_caseNil(): XCTAssertEqual failed: ("nil") is not equal to ("Optional("Hanoi")")

    Sử dụng cách này thì khá là tiện và nhanh, tuy nhiên nó có một nhược điểm là các thông báo lỗi thường không rõ ràng. Ngoài ra nó cũng sẽ không sử dụng được trong các trường hợp đặc biệt.

    Sử dụng XCTUnwrap

    XCTUnwrap() được giới thiệu trên Xcode 11, nó làm nhiệm vụ kiểm tra giá trị optional có nil hay không? nếu nil nó sẽ throw ra lỗi, không nil thì trả về giá trị. Từ đó ta có thể thoải mái sử dụng giá trị đó để thực hiện việc testing.

    func test_address_caseNil() throws {
        let personModel: Person = Person(name: "John", address: nil)
        // result
        let result = try XCTUnwrap(personModel.address)
        XCTAssertEqual(personModel.address, "Hanoi")
    }

    Sử dụng XCTUnwrap giúp source code của chúng ta gọn gàng sạch sẽ hơn rất nhiều so với các cách thông thường khác.

    Để sử dụng được XCTUnwrap bạn nhớ thêm throws cho func test để khi kiểm tra dữ liệu bị nil nó sẽ throw lỗi và đánh dấu test case này bị fail. Nếu bạn muốn thông báo rõ ràng hơn hay đơn giản là bạn muốn viết thông báo lỗi dễ hiểu bạn có thể thêm thuộc tính như sau

     let result = try XCTUnwrap(personModel.address, "Width is nil, please config data for test case")

    Thông báo lỗi ta nhận được sẽ như sau:

    test_address_caseNil(): XCTUnwrap failed: expected non-nil value of type "String" - Width is nil, please config data for test case

    Lúc này thông báo lỗi đã rõ ràng hơn, từ đó bạn có thể xử lí vấn đề một cách nhanh hơn.

    Hi vọng bài viết sẽ giúp cho các bạn có thêm lựa chọn để xử lí các tình huống khi viết Unit Test, từ đó sử dụng nó một cách hiệu quả và phù hợp với các tình huống.

  • Unit Test – Các cách chạy test trên Xcode

    Unit Test – Các cách chạy test trên Xcode

    Thông thường khi các bạn mới vào nghề khi viết xong các test case của mình các bạn thường sử dụng Command + U để chạy. Điều này không sai, tuy nhiên nếu bạn đang thực hiện trên một project lớn thì mình nghĩ bạn không nên dùng cách này vì nó có thể khiến bạn mất rất nhiều thời gian để có được kết quả test. Sau đây mình sẽ giới thiệu cho các bạn một số cách để bạn chạy test case một cách nhanh chóng và hiệu quả hơn.

    Chạy test case trên Test Navigator

    Các bạn có thể tuỳ chọn việc test cả một file hay test từng test case một trên Test Navigator

    1. Chạy test cho cả Target tests: Dùng khi bạn muốn chạy test và lấy báo cáo cho cả target này, khi này Xcode sẽ chạy nhiều test case cùng lúc nên có thể sẽ mất nhiều thời gian
    2. Chạy test cho chỉ một file tests: Dùng khi bạn viết xong toàn bộ test case của một file và muốn chạy test để kiểm tra báo cáo hay khi bạn muốn kiểm tra xem giữa các test case có bị conflict hay không?
    3. Chạy test một case cụ thể: Dùng khi bạn vừa viết xong test case và muốn kiểm tra xem func đã chạy đúng hay chưa, đây là trường hợp bạn nên dùng khi viết UT vì nó chạy nhanh nên tốn ít thời gian mà vẫn đảm bảo mục đích của bạn

    Bạn có thể chạy một hoặc nhiều test case mà bạn muốn bằng cách chọn các test case đó -> chuột phải -> Run x Methods

    Chạy test case trực tiếp trên file Tests

    Khi các bạn viết xong các test case của mình và bấm Command + S, trên func test case của bạn sẽ xuất hiện một button cho bạn chạy test luôn, điều này giúp bạn dễ dàng kiểm tra được test case của mình. Ngoài ra Xcode cũng cung cấp cho chúng ta một nút chạy test cho toàn bộ file ở trên đầu của file. Bạn có thể xem chi tiết ở hình dưới đây

    Chạy lại test case vừa test

    Để chạy lại test các test case bạn vừa mới test thì bạn dùng tổ hợp phím sau:

    ⌃ Control + ⌥ Option + ⌘ Command + G

    Đây là tổ hợp phím rất hữu dụng và được sử dụng thường xuyên vì nó giúp bạn chạy lại test case một cách nhanh chóng khi các bạn phải sửa lại các test case bị fail do viết sai input/output.

    Chạy test tất cả file trong Test Plan

    Khi bạn muốn xem báo cáo tất cả cho file Test Plan của bạn, bạn chỉ cần nhấn tổ hợp phím Command + U.

    Bật Code Coverage trên Sidebar

    Theo mặc định thì code coverage sẽ được bật khi bạn chạy test, tuy nhiên nếu bạn nhỡ tay tắt nó đi mà không biết bật nó ở đâu thì làm theo hướng dẫn sau: Adjust Editor Options -> Code Coverage

    Khi này Xcode sẽ cho bạn biết được dòng code đó của bạn được chạy qua bao nhiêu lần, nếu con số là 0 thì có vẻ bạn chưa có test case nào được viết để test đoạn code đó. Từ dữ liệu đó bạn có thể thực hiện viết thêm test case nếu cần.

    Hi vọng bài viết giúp ích cho các bạn. Xin cảm ơn!

  • Unit Test – Cách tạo mới Test Plan trên XCode

    Unit Test – Cách tạo mới Test Plan trên XCode

    Thông thường thì các ứng dụng phát triển càng lâu thì tính năng của nó sẽ càng nhiều, điều này cũng làm cho khối lượng source code và Unit Test cũng tăng theo, có một số dự án xây dựng theo mô hình module hoá, khi này sẽ có rất nhiều module trong dự án cần thực hiện test nếu chúng ta chạy tất cả các file của project thì nó sẽ tốn rất nhiều thời gian, làm giảm đi năng suất làm việc của bản thân. Vì vậy để thực hiện các test case một cách nhanh chóng và hiệu quả Xcode cho phép chúng ta tự tạo Test Plan theo đúng kế hoạch mà chúng ta muốn. Chúng ta có thể tạo một test plan để test một màn hình riêng biệt cho đến hàng trăm màn hình hoặc có thể là một module mà chúng ta đang làm hay tất cả test case của ứng dụng.

    Tạo mới Test Plan

    Để tạo mới Test Plan ta làm theo các bước như sau:

    Tạo mới test plan

    Đặt tên cho test plan, bạn có thể đặt tên tuỳ ý miễn sao nó đúng với ý nghĩa là được. Sau đó bấm “Create” để Xcode thực hiện.

    Sau khi tạo xong, test plan mới tạo sẽ được thêm vào danh sách, bạn có thể kiểm tra bằng cách thao tác như hình phía dưới đây

    Để thực hiện cấu hình cho test plan mới này chúng ta bấm vào Edit Test Plan ở trên hình.

    Do test plan mới được tạo nên bạn sẽ thấy nó trống, lúc này chưa có một file/class/module/target nào được thêm vào để test nên chúng ta cần thêm nó vào bằng cách bấm vào dấu + trên màn hình dưới đây:

    Tương tự nếu bạn muốn loại bỏ một target nào thì ta có thể bấm dấu – để xoá khỏi test plan.

    Chọn target mà bạn muốn thêm vào test plan và bấm “Add” để thêm target vào test plan.

    Xcode sẽ thêm tất cả các file test chúng ta đã viết vào trong mục Tests, ở đây bạn sẽ nhìn thấy tất cả các file test mà bạn viết, bạn có thể bỏ tích một func hay 1 file để Xcode không chạy phần đó khi run test plan của bạn.

    Để khi chạy test chúng ta xem được Code Coverage thì chúng ta cần đổi giá trị Code Coverage bên Configurations sang ON

    Lúc này khi chạy Test Plan này chúng ta sẽ xem được kết quả bằng cách Report Navigator -> Local -> Test -> Coverage

    Dựa vào báo cáo này bạn sẽ biết được bạn đã viết test case chạy qua được bao nhiêu phần trăm của source code từ đó bạn sẽ có thể đưa ra các action phù hợp.

    Lưu ý Code Coverage chỉ là con số chỉ ra rằng source code test case của bạn đã chạy qua bao nhiêu dòng code, chứ nó không phải là chỉ số đảm bảo độ tin cậy source code của bạn. Vì vậy nó chỉ là điều kiện đủ, code coverage càng cao thì điều đó chứng tỏ Test Case của bạn đã chạy qua càng nhiều dòng code. Để đảm bảo chất lượng source code thì các bạn cần có một chút tư duy về testing, biết xác định các cặp input và output để thực hiện test, cần xác định các điều kiện biên, ngoại lệ, trường hợp lỗi, trường hợp thành công …. thì việc viết test case mới có hiệu quả.

    Hi vọng bài viết giúp ích được cho các bạn!

  • Unit Tests in Swift

    Unit Tests in Swift

    Bạn đang tìm một phương pháp để tăng chất lượng source code? Bạn đang gặp vấn đề về việc source code của bạn có quá nhiều bug? Unit tests là một trong những lựa chọn giúp bạn hạn chế vấn đề đó.

    Hiện nay rất nhiều dự án yêu cầu viết Unit tests nhằm mục đích đảm bảo chất lượng source code, vì vậy bài viết này mình sẽ chia sẻ với các bạn về Unit Tests trong Swift để các bạn có thể trang bị cho mình được một kĩ năng mới, để có thể sẵn sàng và tự tin chiến các dự án hiện tại hoặc trong tương lai.

    Unit Testing là gì?

    Unit tests là tự động chạy và kiểm thử một đoạn mã để đảm bảo nó hoạt động đúng như dự định và đúng với tài liệu yêu cầu.

    Unit tests trong ngôn ngữ lập trình là việc viết các func test để đảm bảo source code hoạt động đúng như tài liệu yêu cầu. Với một đầu vào cụ thể sẽ cho ra một đầu ra cụ thể như tài liệu yêu cầu. Việc viết Unit tests để kiểm tra source code của bạn giúp bạn tự tin hơn khi release hay tái cấu trúc source code, vì bạn sẽ đảm bảo source code của mình chạy đúng mong đợi khi bạn chạy bộ test case của bạn thành công.

    Các quan điểm trái ngược về Unit tests

    Hiện nay có rất nhiều quan điểm trái ngược nhau về việc một dự án có cần phải viết Unit Tests hay không? Rất nhiều Developer thì cho rằng việc viết test tốn quá nhiều thời gian nó làm ảnh hưởng tới việc bàn giao công việc đúng thời hạn. Một số Developer thì cho rằng việc viết Unit tests không đem lại quá nhiều lợi ích mà công việc lại lặp đi lặp lại quá nhàm chán. Tuy nhiên theo mình nếu bạn viết Unit tests đúng cách thì sẽ giúp bạn giảm được thời gian phát triển ứng dụng, tuy thời gian phát triển ban đầu có tăng thêm nhưng bạn sẽ giảm được số lượng bug cơ bản có thể xảy ra từ đó giảm thời gian fix bugs và hạn chế các lỗi phát sinh sau khi sửa.

    Viết Unit Tests với Xcode

    Để giúp các nhà phát triển có thể viết Unit Tests cho các ứng dụng của họ, Apple đã tạo ra XCTest framework. Giờ đây các nhà phát triển có thể sử dụng framework này đê viết Unit tests cũng như chạy các test case để kiểm tra chất lượng source code của họ.

    Một số hàm dùng để kiểm tra của XCTest Framework

    1. XCTAssert(): Nó khá thông dụng có thể sử dụng trong hầu hết các trường hợp, VD: XCTAssert(result == 5)
    2. XCTAssertTrue(): test case của bạn sẽ pass nếu biểu thức kiểm tra có kết quả là true. VD: XCTAssertTrue(view.isHidden)
    3. XCTAssertEqual(a, b), XCTAssertNotEqual: Kiểm tra xem giá trị của 2 biểu thức.
    4. XCTAssertFalse(): ngược với XCTAssertTrue
    5. XCTAssertGreaterThan(a, b): Thường dùng khi bạn kiểm tra 2 giá trị số
    6. XCTAssertGreaterThanOrEqual(a, b): tương tự như XCTAssertGreaterThan, nếu 2 giá trị = nhau thì test case vẫn pass
    7. XCTAssertLessThan, XCTAssertLessThanOrEqual: Tương tự như mục 5 và 6
    8. XCTAssertNil(a), XCTAssertNotNil: Dùng khi cần kiểm tra một var/func có nil hay không
    9. XCTAssertNoThrow() Dùng khi cần kiểm tra xem func có throw lỗi hay không
    10. XCTAssertThrowsError() dùng khi cần kiểm tra func có throw error và kiểm tra được error

    Để các bạn dễ hình dung hơn mình sẽ đưa ra một ví dụ như sau:

    Tài liệu yêu cầu bạn phải viết một hàm để tính chu vi của hình chữ nhật khi biết chiều dài và chiều rộng của nó. Ta biết chu vi của hình chữ nhật chính là tổng tất cả các cạnh của nó, vì vậy ta có thể sẽ viết func như sau:

    class Regtangle {
        // hàm tính chu vi hình chữ nhật
        class func perimeter(width: Int, height: Int) -> Int {
           (width + height) * 2
        }
    }

    Để viết bắt đầu viết test case chúng ta sẽ cần tạo file test như sau:

    Chuột phải vào thư mục cần tạo file -> chọn new file -> Unit Test Case Class -> Next

    Đặt tên cho file test, trong trường hợp này mình đang cần test class Regtangle nên mình đặt tên như hình -> Next

    Sau khi tạo file chúng ta XCode sẽ tạo sẵn cho chúng ta một số đoạn code cơ bản như sau:

    import XCTest
    // thêm target cần test
    @testable import UTXcode14
    
    final class RegtangleTests: XCTestCase {
    
        override func setUpWithError() throws {
            // Put setup code here. This method is called before the invocation of each test method in the class.
        }
    
        override func tearDownWithError() throws {
            // Put teardown code here. This method is called after the invocation of each test method in the class.
        }
    
        func testExample() throws {
            // This is an example of a functional test case.
            // Use XCTAssert and related functions to verify your tests produce the correct results.
            // Any test you write for XCTest can be annotated as throws and async.
            // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error.
            // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards.
        }
    
        func testPerformanceExample() throws {
            // This is an example of a performance test case.
            self.measure {
                // Put the code you want to measure the time of here.
            }
        }
    
    }
    

    func testPerformanceExample() đây là hàm để kiểm tra hiệu suất của đoạn code, nếu bạn không cần kiểm tra thì bỏ nó đi giúp mỗi lần chạy test của bạn sẽ nhanh hơn đáng kể.

    Bây giờ chúng ta đã có thể viết test case để kiêm tra class Regtangle. Đối với func tính chu vi như vậy thì ta sẽ cần dựa vào yêu cầu và phân tích tích bài toán một chút.

    Chúng ta hiểu rằng chiều cao và chiều rộng của hình chữ nhật phải là số lớn hơn 0, chu vi của hình chữ nhật thì bằng tổng chiều dài bốn cạnh, vậy nên chúng ta sẽ cần viết các test case với trường hợp như sau:

    1. width và height đều lớn hơn 0: Đầu ra là (width + height) * 2
    2. width <= 0, height > 0: đầu ra cần phải là một thông báo lỗi
    3. width > 0, height <= 0: Đầu ra cần phải là một thông báo lỗi
    4. width <= 0, height <= 0: Đầu ra cần phải là một thông báo lỗi

    Đối với case số 1 yêu cầu dữ liệu đầu vào cả width và height đều phải là một số > 0 thì ta viết như sau:

       // case width > 0 and height > 0
       func test_perimeter_case1() {
            // input
            let width: Int = 3
            let height: Int = 2
            // expectation
            let expectation = 10
            // run code
            let result = Regtangle.perimeter(width: width, height: height)
            
            // verify
            XCTAssertEqual(result, expectation)
        }

    Chạy test ta thu đươc kết quả như hình, dấu tích xanh thể hiện kết quả với expectation là bằng nhau, có nghĩa là trong trường hợp này hàm Regtangle.perimeter() đã chạy đúng.

    Tiếp theo chúng ta sẽ viết tiếp test case số 2, width <=0 và height > 0, đây là trường hợp chiều rộng nhỏ hơn 0 vì vậy nó là một trường hợp lỗi, mình sẽ mong đợi một thông báo lỗi “Width must be greater than zero”. Vậy nên mình viết code như hình dưới

    Lúc này Xcode sẽ báo lỗi như hình trên là do chúng ta đang so sánh 2 kiểu dữ liệu khác nhau. Quay lại hàm tính chu vi hình chữ nhật thì chúng ta thấy không có logic kiểm tra width và height điều này khiến cho func này không đảm bảo tính đúng đắn của nó.

    Vậy viết func tính chu vi như nào mới đúng? các bạn có thể tham khảo một số cách viết của mình như sau:

    Cách 1: Sử dụng Result để trả về kết quả

    // equatable để tiện cho việc so sánh khi viết Unit test
    struct MyError: Error, Equatable {
        let message: String
    }
    
    class Regtangle {
        // hàm tính chu vi hình chữ nhật
        class func perimeter(width: Int, height: Int) -> Result<Int, MyError> {
            if width <= 0 && height <= 0 {
                return .failure(MyError(message: "Width and height must be greater than zero"))
            } else if width <= 0 {
                return .failure(MyError(message: "Width must be greater than zero"))
            } else if height <= 0 {
                return .failure(MyError(message: "Height must be greater than zero"))
            } else {
                let perimeter = (width + height) * 2
                return .success(perimeter)
            }
        }
    }

    Cách 2: Sử dụng throw để đẩy ra lỗi

    struct MyError: Error, Equatable {
        let message: String
    }
    
    class Regtangle {
        // hàm tính chu vi hình chữ nhật
        class func perimeter(width: Int, height: Int) throws -> Int {
            if width <= 0 && height <= 0 {
                throw MyError(message: "Width and height must be greater than zero")
            } else if width <= 0 {
                throw MyError(message: "Width must be greater than zero")
            } else if height <= 0 {
                throw MyError(message: "Height must be greater than zero")
            } else {
                return (width + height) * 2
            }
        }
    }

    Trong bài viết này mình sẽ hướng dẫn các bạn viết test case khi sử dụng throw, mình sẽ viết tổng cộng 7 test cases để thực hiện test func này, trong đó bao gồm 4 test cases để test logic chính và 3 cases để test giá trị biên. Cụ thể mình sẽ thực hiện như sau:

    import XCTest
    @testable import UTXcode14
    
    final class RegtangleTests: XCTestCase {
    
        override func setUpWithError() throws {
            // Put setup code here. This method is called before the invocation of each test method in the class.
        }
    
        override func tearDownWithError() throws {
            // Put teardown code here. This method is called after the invocation of each test method in the class.
        }
    
        // case width > 0 and height > 0
        func test_perimeter_case1() throws {
            // precontidtion
            let width: Int = 3
            let height: Int = 2
            // expectation
            let expectation = 10
            // run code
            XCTAssertNoThrow(try Regtangle.perimeter(width: width, height: height))
            let result = try Regtangle.perimeter(width: width, height: height)
            
            // verify
            XCTAssertEqual(result, expectation)
        }
        
        // case width < 0 and height > 0
        func test_perimeter_case2() throws {
            // precontidtion
            let width: Int = -3
            let height: Int = 2
            // expectation
            let expectation = MyError(message: "Width must be greater than zero")
            // run code
            XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
                XCTAssertEqual(error as? MyError, expectation)
            }
        }
        
        // case width > 0 and height < 0
        func test_perimeter_case3() throws {
            // precontidtion
            let width: Int = 3
            let height: Int = -2
            // expectation
            let expectation = MyError(message: "Height must be greater than zero")
            // run code
            XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
                XCTAssertEqual(error as? MyError, expectation)
            }
        }
        
        // case width < 0 and height < 0
        func test_perimeter_case4() throws {
            // precontidtion
            let width: Int = -3
            let height: Int = -2
            // expectation
            let expectation = MyError(message: "Width and height must be greater than zero")
            // run code
            XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
                XCTAssertEqual(error as? MyError, expectation)
            }
        }
        
        // case width = 0 and height > 0, test giá trị biên của width
        func test_perimeter_case5() throws {
            // precontidtion
            let width: Int = 0
            let height: Int = 2
            // expectation
            let expectation = MyError(message: "Width must be greater than zero")
            // run code
            XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
                XCTAssertEqual(error as? MyError, expectation)
            }
        }
        
        // case width = 0 and height > 0, test giá trị biên của height
        func test_perimeter_case6() throws {
            // precontidtion
            let width: Int = 2
            let height: Int = 0
            // expectation
            let expectation = MyError(message: "Height must be greater than zero")
            // run code
            XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
                XCTAssertEqual(error as? MyError, expectation)
            }
        }
        
        // case width = 0 and height = 0, test giá trị biên của cả width và height
        func test_perimeter_case7() throws {
            // precontidtion
            let width: Int = 0
            let height: Int = 0
            // expectation
            let expectation = MyError(message: "Width and height must be greater than zero")
            // run code
            XCTAssertThrowsError(try Regtangle.perimeter(width: width, height: height)) { error in
                XCTAssertEqual(error as? MyError, expectation)
            }
        }
    }

    Chạy test (Command U) chúng ta được kết quả như sau:

    Tất cả các test case của chúng ta đều passed, điều này chứng minh func của bạn đã đáp ứng hết tất cả yêu cầu mà bạn đặt ra

    Hi vọng bài viết sẽ giúp cho các bạn có thêm kiến thức để nâng cao năng lực của bản thân.

  • Fake GPS location on Xcode

    Fake GPS location on Xcode

    Ở phần trước mình đã hướng dẫn các bạn các cách để fake GPS location trên Simulator của iPhone. Nếu các bạn muốn tìm hiểu thêm thông tin thì có thể tham khảo ở đường link: HƯỚNG DẪN CÁCH FAKE GPS TRÊN SIMULATOR

    Trong bài này mình sẽ hướng dẫn các bạn Fake GPS location on Xcode nhằm mục đích giúp các bạn có thêm các cách để giảm thời gian và dễ dàng test các ứng dụng liên quan tới GPS, location services. Đặc biệt hữu dụng với các ứng dụng yêu cầu người dùng phải di chuyển kiểu như app chạy bộ, đạp xe, chỉ đường, hướng dẫn … v.v.

    Giải thích về ý tưởng

    Để dễ dàng cho việc test các tính năng yêu cầu người dùng ứng dụng phải di chuyển, chúng ta sẽ sử dụng cách Fake GPS location bằng cách sử dụng GPX file trên Xcode. GPX file cho phép chúng ta thêm các vị trí và thời gian di chuyển đến vị trí đó, từ đó ta có thể tạo ra một danh sách các điểm cần di chuyển đến để thực hiện test ứng dụng mà không cần di chuyển thực tế. GPX file cho phép ta có thể tạo ra các kịch bản test di chuyển một cách dễ dàng và tiết kiệm thời gian và công sức. Ngoài ra ta có thể sử dụng lại được nhiều lần và dễ dàng chỉnh sửa theo các kịch bản test.

    Từ các tính năng như trên chúng ta có thể tạo ra một ứng dụng chuyên để Fake GPS Location từ đó giả lập vị trí của iPhone.

    NOTE

    Đây là fake GPS location của thiết bị luôn, và nó hoạt động và ảnh hưởng lên tất cả các ứng dụng đang sử dụng Map, Location Services. Vậy nên các bạn lưu ý khi sử dụng nha.

    Hướng dẫn Fake Location GPS trên XCode sử dụng GPX file

    Để tiện cho việc demo các bạn có thể tải xuống source ở link dưới đây:

    Bước 1: Tạo file GPX để fake GPS Location trên Xcode

    Sử dụng Xcode mở project DemoGPXMapKit lên -> Bấm chuột phải vào tạo new file…

    Fake GPS location on Xcode

    Khi của sổ mở lên, ở ô tìm kiếm bạn điền từ khoá “GPX” thì sẽ được kết quả như hình dưới đây

    Fake GPS location on Xcode

    Bấm Next và đặt tên cho file, ở ví dụ này mình sẽ đặt là mydinh-hanoi. Đặt tên xong Xcode sẽ tạo cho các bạn một file và có sẵn nội dung là một điểm.

    Các bạn có thể thay đổi file GPX tuỳ theo trường hợp mà bạn muốn. Ở đây mình muốn Fake GPS Location về Sân vận động Mỹ Đình nên mình sửa lại file như sau:

    <?xml version="1.0"?>
    <gpx version="1.1" creator="Xcode">
        <wpt lat="21.02025349623149" lon="105.76408736691972">
            <name>My-dinh</name>
            <time>2014-09-24T14:55:37Z</time>
        </wpt>
    </gpx>
    

    Về toạ độ lat, lon các bạn có thể sử dụng Google Map để lấy -> bấm chuột phải vào vị trí bạn muốn lấy vị trí sẽ hiển thị như hình và bạn chọn vào hàng có toạ độ là nó tự copy toạ độ cho các bạn, rồi các bạn paste vào file GPX để thay đổi vị trí một cách dễ dàng.

    Fake GPS location on Xcode

    Bước2: Chỉnh sửa scheme để file GPX fake GPS Location tự động ăn khi chạy ứng dụng

    Chọn Scheme -> Edit Scheme như hình dưới

    Fake GPS location on Xcode

    Một popup hiển thị lên, lúc này bạn chọn Run -> Options.
    – Ở mục CoreLocation tích vào Allow Location Simolation.
    – Ở mục Default Location chọn file gpx của các bạn, trường hợp này của mình là mydinh-hanoi. Nếu không chọn thì mặc định nó sẽ là None và khi đó nó sẽ ăn vào location của Simulator

    Fake GPS location on Xcode

    Thực hiện Build(Command + R) ứng dụng để ứng dụng sử dụng file GPX.

    Khi này ở thanh Debug chúng ta sẽ có thêm icon Location để cho phép chúng ta thay đổi vị trí Fake GPS location một cách dễ dàng và nhanh chóng hơn.

    Fake GPS location on Xcode

    Kết quả thu được như sau:

    Fake GPS location on Xcode

    Các bạn có thể tạo ra nhiều file GPX với nhiều vị trí khác nhau để thuận tiện cho việc test, hoặc có thể sửa trực tiếp file GPX rồi chọn lại mà không cần build lại ứng dụng.

    Fake GPS Location di chuyển theo đường đi bằng file GPX

    Chúng ta sẽ tạo mới một file như các bước mình đã hướng dẫn ở đầu bài. Nội dung thì sửa lại như sau:

    <?xml version="1.0"?>
    <gpx version="1.1" creator="Xcode">
        <wpt lat="21.02186996901372" lon="105.7645261741194">
            <name>Cupertino</name>
            <time>2014-09-24T14:05:30Z</time>
        </wpt>
        <wpt lat="21.021606653375308" lon="105.76616386527535">
            <name>Cupertino</name>
            <time>2014-09-24T14:05:40Z</time>
        </wpt>
        <wpt lat="21.019302621702572" lon="105.76618737280388">
            <name>Cupertino</name>
            <time>2014-09-24T14:05:50Z</time>
        </wpt>
    </gpx>

    Ở đây mình có thêm vào 3 waypoints để fake GPS location, nhằm giả lập việc di chuyển qua các điểm này. Các bạn để ý kỹ thì mình có thay đổi thời gian của các waypoint tăng dần và cách nhau 10s. Các bạn có thể tính toán vận tốc và quãng đường để thực hiện giả lập một cách chân thực nhất, ví dụ như tốc độ của ô tô với máy bay thì sẽ khác nhau vì vậy cùng quãng đường thời gian cũng sẽ khác nhau.

    Giờ khi các bạn chọn icon location sẽ hiển thị ra file bạn mới tạo và có thể thay đổi luôn mà không cần phải build lại nữa, như mình mới tạo file ride-mydinh-hanoi

    Kết quả chúng ta sẽ thu được như sau

    Tuy nhiên ta có thể thấy nó cứ lặp đi lặp lại vô hạn mà không dừng lại tại điểm cuối cùng. Để cho nó dừng lại ở điểm cuối cùng thì chúng ta sẽ sử dụng thêm một waypoint nữa và thay đổi vị trí không đáng kể và tăng thời gian di của điểm này cách xa so với điểm gần cuối như sau:

    <?xml version="1.0"?>
    <gpx version="1.1" creator="Xcode">
        <wpt lat="21.02186996901372" lon="105.7645261741194">
            <name>Cupertino</name>
            <time>2014-09-24T14:05:30Z</time>
        </wpt>
        <wpt lat="21.021606653375308" lon="105.76616386527535">
            <name>Cupertino</name>
            <time>2014-09-24T14:05:40Z</time>
        </wpt>
        <wpt lat="21.019302621702572" lon="105.76618737280388">
            <name>Cupertino</name>
            <time>2014-09-24T14:05:50Z</time>
        </wpt>
        <wpt lat="21.019302611702572" lon="105.76618737280388">
            <name>Cupertino</name>
            <time>2014-09-24T15:05:50Z</time>
        </wpt>
    </gpx>

    Bạn để ý kĩ chỗ mình bôi đậm sẽ hiểu rõ nguyên lý hoạt động của nó.

    Từ đây bạn có thể mở rộng ra bằng cách tạo thêm nhiều file GPX với các cung đường đa dạng để phục vụ cho việc test ứng dụng của các bạn khi cần.

    Mình hi vọng bài viết có thể giúp mọi người làm việc một cách dễ dàng và hiệu quả hơn.

  • How to enable UT Coverage on Xcode?

    How to enable UT Coverage on Xcode?

    You want to check your UT index?
    You want to display the coverage index on xcode to know if your code has reached the standard?
    How to show Coverage index on xcode?
    How to enable UT Coverage on XCode?
    Those are the questions I get asked often, but there aren’t many tutorials on the internet yet. So today I will guide you to enable Code Coverage on Xcode

    How to enable UT Coverage on Xcode 13.4.1 or below?

    For projects using Xcode 13 or below to create, we do the following:

    Step 1: Select Scheme -> edit Scheme -> a popup is displayed

    Step 2: In the left menu of the popup select Test, then in the upper menu of the popup select option -> tick Code Coverage for

    Step 3: Run test app (command + U)

    How to enable UT Coverage on Xcode 14.0 or later?

    For projects using Xcode 14 or later to create, we do the following:

    Step 1: Select Scheme -> edit Scheme -> a popup is displayed

    How to enable UT Coverage on XCode

    Step 2: In the left menu of Popup select Test, then hover on Test Plan as shown and then click the button to go to settings.

    How to enable UT Coverage on XCode

    Step 3: Change code coverage to On

    How to enable UT Coverage on XCode

    If you don’t need to test UI, you can remove the test plan for UI to make Unit tests run faster

    How to enable UT Coverage on XCode

    Step 4: Run test (command + U), ta thu được kết quả như sau

    How to enable UT Coverage on XCode

    I hope it can help!

  • Hướng dẫn cách Fake GPS trên Simulator

    Hướng dẫn cách Fake GPS trên Simulator

    Hi, trong quá trình phát triển các ứng dụng iOS, đôi khi chúng ta sẽ được phát triển các tính năng liên quan tới bản đồ, một số ứng dụng còn cần phải sử dụng Location Service để hiển thị vị trí của người dùng. Vì vậy khi phát triển ứng dụng bạn sẽ cần phải kiểm tra ứng dụng của mình xem nó chạy đúng chưa, hiển thị đúng vị trí trên bản đồ chưa? Nếu chúng ta cầm thiết bị chạy đi chạy lại thì thật quá tốn công, tốn sức. Thấu hiểu nỗi khổ của các iOS developers Apple đã phát triển tính năng Fake GPS trên Simulator giúp cho việc kiểm tra ứng dụng của mình một cách dễ dàng và đỡ mất công mất sức hơn.

    Fake GPS trên Simulator – Di chuyển đến trụ sở chính của Apple

    Để bật tính năng này chúng ta mở Simulator lên, trên Menu bar của Simulator chọn Features -> Location -> Apple như hình dưới đây

    fake gps on simulator

    Kết quả chúng ta sẽ được vị trí GPS ở trụ sở của Apple.

    Fake GPS trên Simulator – Di chuyển đến vị trí bất kì trên bản đồ

    Việc fake GPS trên Simulator đến vị trí trung tâm Apple không giúp ích nhiều cho việc kiểm tra ứng dụng của bạn, vì vậy mình sẽ hướng dẫn các bạn cách để Fake GPS trên Simulator đến vị trí bất kì trên bản đồ. Để làm được điều này chúng ta cần Kinh độ và Vĩ độ của điểm chúng ta cần fake GPS. Các bạn có thể lên Google Map để lấy toạ độ nhá. Ví dụ mình sẽ lấy toạ độ của Đền Ngọc Sơn trên Hồ Hoàn Kiếm ở Hà Nội.

    Để ý hình mình có khoanh, Ta sẽ lấy toạ độ (lat, long) theo thứ tự từ trái qua phải là Latitude và Longitude ở trên URL của google map. Trong ví dụ này Latitude: 21.0298318Longitude: 105.8532851.

    Khi lấy được toạ độ cần fake GPS trên Simulator rồi thì ta sẽ làm như sau:
    Trên Menu bar của Simulator -> chọn Features -> Location -> Custom Location… -> Điền Latitude và Longitude vào và bấm OK như hình dưới.

    Vậy là chúng ta đã có thể fake GPS đên mọi nơi mà chúng ta cần để kiểm tra ứng dụng của mình.

    NOTE: Có một lưu ý là khi các bạn copy Latitude và Longitude từ Google đôi khi ngôn ngữ không giống với simulator nên simulator nó không nhận, bạn hãy để ý và thay dấu chấm “.” <-> thành dấu phẩy “,” hoặc ngược lại nhé.

    Fake GPS trên Simulator – Fake trường hợp vị trí chuyển động liên tục.

    Trong thực tế có một số ứng dụng yêu cầu ta phải hiển thị vị trí của người dùng chính xác và liên tục, tuy nhiên để kiểm tra trường hợp này một cách mượt mà thì sử dụng các cách phía trên là bất khả thi và tốn rất nhiều thời gian, vì vậy apple đã cung cấp một số cách để thuận tiện cho việc kiểm tra vị trí di chuyển đó là: City Run, City Bicycle Ride và Freeway Drive.
    Trên Menu bar của Simulator -> chọn Features -> Location -> City Run hoặc City Bicycle Ride hoặc Freeway Drive.

    Vậy là bạn đã có thể ngồi 1 chỗ và test được việc di chuyển trên ứng dụng của mình mà không tốn một giọt mồ hôi nào.

    Hiện tại Apple chỉ hỗ trợ 3 loại di chuyển như trên vì vậy nó khá hạn chế trong việc kiểm thử, trong trường hợp các bạn cần linh hoạt hơn thì chúng ta có thể sử dụng file GPX để fake GPS trên Simulator chủ động hơn, tuy nhiên cách này sẽ phức tạp hơn một chút. Vì vậy mình sẽ hướng dẫn các bạn ở bài viết tiếp theo nhé!

  • Làm cách nào để thực hiện cuộc gọi, gọi FaceTime và gửi SMS trong ứng dụng sử dụng Swift?

    Làm cách nào để thực hiện cuộc gọi, gọi FaceTime và gửi SMS trong ứng dụng sử dụng Swift?

    Hiện nay hầu hết các ứng dụng di động đều có tính năng liên lạc nhằm mục đích giúp người sử dụng dễ dàng liên hệ được với bộ phận chăm sóc khách hàng. Để làm được việc này thì Apple có cung cấp một URL Scheme để thực hiện việc này.

    URL Scheme Mail

    Để có thể sử dụng được tính năng gửi mail thông qua app của Apple chúng ta cần cấu hình dự án cho phép sử dụng URL schemes “mailto” như sau:

    Mở file info.plist và thêm Queried URL Shemes -> add item và đặt trường value với giá trị là mailto

    Để thực hiện được việc gửi mail chúng ta thực hiện đoạn code như sau:

      func mail(to: String, cc: String = "", subject: String = "", body: String = "") {
            
            var mailURLString: String = "mailto:"
            
            // add to
            mailURLString += to
            
            // add cc
            mailURLString += "?cc=\(cc)"
            
            // add subject
            if let subjectEncode = subject.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) {
                mailURLString += "&subject=\(subjectEncode)"
            }
            
            // add content
            if let bodyEncode = body.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) {
                mailURLString += "&body=\(bodyEncode)"
            }
            
            // check url
            if let mailURL = URL(string: mailURLString), UIApplication.shared.canOpenURL(mailURL) {
                // open app mail with url
                UIApplication.shared.open(mailURL)
            }
        }

    Bây giờ bất kể chỗ nào chúng ta dùng để gửi mail đều có thể call func này để thực hiện việc gửi mail ví dụ như sau:

    mail(to: "[email protected]", cc: "[email protected]", subject: "Techover.io", body: "New post")

    URL Scheme Phone

    Tương tự như Mail việc gọi điện app cũng có 1 scheme cho phép thực hiện việc này.

        func tel(to: String) {
            if let telURL = URL(string: "tel:\(to)"), UIApplication.shared.canOpenURL(telURL) {
                UIApplication.shared.open(telURL)
            }
        }

    URL Scheme FaceTime

        func faceTime(to: String) {
            if let telURL = URL(string: "facetime-audio://\(to)"), UIApplication.shared.canOpenURL(telURL) {
                UIApplication.shared.open(telURL)
            }
        }

    URL Scheme SMS

        func sms(to: String) {
            if let telURL = URL(string: "sms:\(to)"), UIApplication.shared.canOpenURL(telURL) {
                UIApplication.shared.open(telURL)
            }
        }

    Ngoài ra chúng ta còn có thêm các Apple URL Scheme khác như MAP Links , iTunes Links, YouTube Links … Anh em có thể tham khảo thêm tài liệu của Apple ở link sau: https://developer.apple.com/library/archive/featuredarticles/iPhoneURLScheme_Reference/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007899-CH1-SW1

  • IBInspectable and IBDesignable in Swift

    IBInspectable and IBDesignable in Swift

    Xin chào mọi người, bài viết này mình xin giới thiệu với các bạn về IBInspectable và IBDesignable trong swift.

    IBInspectable

    Khi các bạn thực hiện code UI bằng Interface builder của Xcode, nó sẽ hiển thị cho các bạn một số các thuộc tính cơ bản để các bạn có thể chỉnh sửa. Hình dưới đây là Atributes Inspector của UIView.

    Inspectable-and-IBDesignable

    Có bao giờ bạn muốn thêm các thuộc tính của một UI trong tab Attributes Inspector chưa? Nếu bạn có ý định này thì xin chúc mừng. IBInspectable sẽ giúp bạn làm được việc này.

    IBInspectable giúp cho bạn có thể thêm được rất nhiều các thuộc tính vào tab Attributes Inspector từ đó giúp các bạn dễ dàng chỉnh sửa nó trên Interface builder của Xcode một cách dễ dàng.

    Vậy để sử dụng IBInspectable thêm các thuộc tính vào Interface builder của xCode chúng ta làm như sau:

    Ở đây mình sẽ làm một ví dụ để thêm thuộc tính cho UIView

    Như bạn đã biết thì UIView trên Interface builder không có các thuộc tính như cornerRadius(bo góc), borderColor(màu viền), borderWidth(độ rộng viền)… Vậy trong ví dụ này mình sẽ thêm các thuộc tính này vào Attributes inspector của UIView.

    Đầu tiên mình tạo một class CommonView kế thừa lại UIView như sau:

    class CommonView: UIView {
        // thêm thuộc tính để bo góc cho View
        @IBInspectable
        var cornerRadius: CGFloat = 4 {
            didSet {
                clipsToBounds = true
                layer.cornerRadius = cornerRadius
            }
        }
        
        // thêm thuộc tính để đặt độ dày của viền cho View
        @IBInspectable
        var borderWidth: CGFloat = 1 {
            didSet {
                layer.borderWidth = borderWidth
            }
        }
        // thêm thuộc tính để sửa màu viền cho View
        @IBInspectable
        var borderColor: UIColor = .red {
            
            didSet {
                layer.borderColor = borderColor.cgColor
            }
        }
    }

    Để sử dụng CommonView thì chúng ta mở file Storyboard hoặc file xib lên và kéo một UIView vào, sau đó đổi class từ UIView(mặc định) sang CommonView, vậy là xong.

    Kết quả chúng ta sẽ được như sau:

    Inspectable-and-IBDesignable
    Các thuộc tính Corner Radius, Border Witdh, Border color đã được thêm vào Attributes Inspector băng thuộc tính @IBInspectable

    Vậy là chúng ta đã thêm được các thuộc tính vào Attributes Inspector của Xcode, tuy nhiên chúng ta cần phải build app lên thì mới thấy sự thay đổi. Sao nó không thay đổi ngay khi chúng ta sửa giá trị như các thuộc tính khác? Vì một mình IBInspectable thì không làm được vì vậy các nhà phát triển của Apple mới đẻ ra IBDesignable để làm việc này.

    IBDesignable

    IBDesignable cho phép chúng ta xem trực tiếp các thay đổi của view trong storyboard hoặc trong file xib mà không cần phải run ứng dụng.

    Để sử dụng IBDesignable thì chúng ta chỉ cần thêm @IBDesignable vào đằng trước class mà chúng ta muốn và override lại func prepareForInterfaceBuilder() để nó update giá trị và hiển thị lên trên Interface builder, trong ví dụ này mình để nó ở trước class CommonView của mình như sau:

    @IBDesignable
    class CommonView: UIView {
        // set giá trị để hiển thị cho Interface builder
        override func prepareForInterfaceBuilder() {
            setupView()
        }
        // setup view
        private func setupView() {
            self.layer.cornerRadius = cornerRadius
            self.layer.borderWidth = borderWidth
            self.layer.borderColor = borderColor.cgColor
        }
    
        @IBInspectable
        var cornerRadius: CGFloat = 4 {
            didSet {
                clipsToBounds = true
                layer.cornerRadius = cornerRadius
            }
        }
        
        @IBInspectable
        var borderWidth: CGFloat = 1 {
            didSet {
                layer.borderWidth = borderWidth
            }
        }
        
        @IBInspectable
        var borderColor: UIColor = .red {
            
            didSet {
                layer.borderColor = borderColor.cgColor
            }
        }
    }

    CHÚ Ý: Bạn cần phải override lại func prepareForInterfaceBuilder() và set lại các thuộc tính để nó có thể update giá trị cho interface builder.

    Bây giờ chúng ta chỉ cần kéo UIView vào là nó sẽ tự apply các thuộc tính và khi sửa tại Attributes inspector thì nó sẽ được update ngay mà không cần phải build ứng dụng để kiểm tra lại UI.

    Kết quả chúng ta được như hình dưới đây:

    IBInspectable and IBDesignable uiview

    Trong trường hợp các bạn muốn làm common và không cho sửa thuộc tính nào trên interface builder thì bạn chỉ cần bỏ IBInspectable của thuộc tính đó đi là được.

    Tổng kết

    Vậy là mình đã giới thiệu cho các bạn một phương pháp để thực hiện làm common rất hiệu quả và tiết kiệm thời gian khi làm ứng dụng di động trên iOS. Từ ví dụ common view này chúng ta có thể phát triên cho các common khác như UILabel, UIButton … Mình hi vọng bài viết sẽ giúp ích cho các bạn trong quá trình học hỏi và phát triển ứng dụng iOS.