ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift(UIKit) 를 SwiftUI처럼 쓰는 방법
    SwiftUI 2021. 12. 24. 13:28

    1. Builder Pattern 사용

    : 명명을 Worker로 변경(Ribs에서 Builder 가 충돌나기 때문)

    dynamicMemberLookup에 대한 상세 설명 및 출처 : https://kkimin.tistory.com/83

    import UIKit
    
    @dynamicMemberLookup
    struct Worker<Base: AnyObject> {
    
    	private var base: Base
    
    	init(_ base: Base) {
    		self.base = base
    	}
    
    	subscript<Value>(dynamicMember keyPath: ReferenceWritableKeyPath<Base, Value>) -> (Value) -> Worker<Base> {
    		{ [base] value in
    			base[keyPath: keyPath] = value
    			return Worker(base)
    		}
    	}
    
    	@discardableResult
    	func build() -> Base {
    		return base
    	}
    }
    
    extension Worker where Base: UIView {
    	@discardableResult
    	func add(to view: UIView, constraints: (Base) -> [NSLayoutConstraint]) -> Base {
    		return add(to: view)
    			.activate(constraints)
    			.build()
    	}
    
    	@discardableResult
    	func add(to view: UIView) -> Worker<Base> {
    		base.addSubview(view)
    		return self
    	}
    
    	@discardableResult
    	func activate(_ constraints: (Base) -> [NSLayoutConstraint]) -> Worker<Base> {
    		base.translatesAutoresizingMaskIntoConstraints = false
    		NSLayoutConstraint.activate(constraints(base))
    		return self
    	}
    
    	@discardableResult
    	func background(color: UIColor) -> Worker<Base> {
    		base.backgroundColor = color
    		return self
    	}
    
    	func borderRadius(_ r: CGFloat) -> Worker<Base> {
    		base.layer.cornerRadius = r
    		base.clipsToBounds = true
    		return self
    	}
    }
    
    protocol Workable: AnyObject {}
    
    extension Workable {
    	var builder: Worker<Self> {
    		Worker(self)
    	}
    }
    
    extension NSObject: Workable {}
    
    extension Worker where Base: UILabel {
    	func text(_ text: String) -> Worker<Base> {
    		base.text = text
    		return self
    	}
    	
    	func numberOfLines(_ lines: Int = 0) -> Worker<Base> {
    		base.numberOfLines = lines
    		return self
    	}
    }
    
    extension Worker where Base: UIButton {
    	func addImage(_ image: UIImage = .add) -> Worker<Base> {
    		base.setImage(image, for: .normal)
    		return self
    	}
    }
    }
    
    // 이런식으로 많은 확장 가능.

    사실 위처럼 하지 않고, UI를 생성할때 아래 같은 식으로 작성해도 되지만 위처럼 하면 더 많은 커스텀이 가능하다.

    //  이런식으로도 가능하지만
    private lazy var tableView: UITableView = {
    		let tableView = UITableView()
    		tableView.translatesAutoresizingMaskIntoConstraints = false
    		tableView.delegate = self
    		tableView.register(cellType: CustomCell.self)
    		tableView.rowHeight = 100
    		return tableView
    	}()
        
    // builder를 쓰면 아래처럼 작성 가능 (기능들은 더 확장으로 추가되어야함)
    private lazy var testView = UITableView().builder
        .translatesAutoresizingMaskIntoConstraints(false)
        .build()

     

    ++ Then 도 비슷한 형식으로 추가

    public protocol Then {}
    
    extension NSObject: Then {}
    
    extension Then where Self: AnyObject {
    	public func then(_ block: (Self) throws -> Void) rethrows -> Self {
    		try block(self)
    		return self
    	}

    2. UIPreviewProvider 사용하기

    Preview 사용 조건

    • Xcode 11 이상
    • macOS Catalina 이상
    • iOS 13+
    enum DeviceType {
    	case iPhoneSE2
    	case iPhone8
    	case iPhone12Pro
    	case iPhone12ProMax
    
    	func name() -> String {
    		switch self {
    			case .iPhoneSE2:
    				return "iPhone SE"
    			case .iPhone8:
    				return "iPhone 8"
    			case .iPhone12Pro:
    				return "iPhone 12 Pro"
    			case .iPhone12ProMax:
    				return "iPhone 12 Pro Max"
    		}
    	}
    }
    
    #if canImport(SwiftUI)
    import SwiftUI
    extension UIViewController {
    
    	private struct Preview: UIViewControllerRepresentable {
    		let viewController: UIViewController
    
    		func makeUIViewController(context: Context) -> UIViewController {
    			return viewController
    		}
    
    		func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
    		}
    	}
    
    	func showPreview(_ deviceType: DeviceType = .iPhone12Pro) -> some View {
    		Preview(viewController: self).previewDevice(PreviewDevice(rawValue: deviceType.name()))
    	}
    }
    #endif

     

    이렇게 선언해 두고

     

    실제로 보고싶은 ViewController 를 아래처럼 실행시킨다. - 아래 따로 작성 (당연히 View로도 가능)

    #if canImport(SwiftUI)
    import SwiftUI
    
    struct VCPreView: PreviewProvider {
    	static var previews: some View {
    		ViewController().showPreview(.iPhone8)
    	}
    }
    #endif

    만약?

    이렇게 했는데 자동으로 preview가 나오지 않는다?

    To open the preview canvas, just go to Editor -> Canvas

    Or do Alt + Command + Enter

    하면 나올거다.

     

    이렇게 하면 상황별로 보기도 좋고, 또 코드로 view를 짠 경우 확인에도 좋다. 대충 아래처럼 미리 나오는거다!! - 확장성 및 기능도 다양함!!

     

     

     

    출처 및 참고 : https://ios-development.tistory.com/488, https://fluffy.es/xcode-previews-uikit/

     

    728x90

    댓글

Designed by Tistory.