introduce
Writing this article is also a few days ago in the development of an interface when a whim. We often encounter lazy view loading scenarios, such as a UIViewController containing multiple child UIViewControllers and a UIView containing multiple child UIViews, but these child UIViews /UIViewController will not be displayed at the same time. You usually use show/hide logic for control, and you want to initialize only when you actually use it for performance reasons. However, the daily use of processing methods are tedious or inadequate, so I hope to abstract a simple syntax sugar tool to achieve this ability.
The instance
Take this merchandise floor for example,Has gone
/Cold storage icon
/attribute
/The label
May not display, you want to display the actual initialization.
Common implementations
Use optional values
class UITableView {
private var iconImageView: UIImageView?
func bind(props: CellProps) {
/ / show
if let imageIconURL = props.imageIconURL {
// Determine whether to initialize
if iconImageView = = nil {
let imageView = UIImageView()
contentView.addSubview(imageView)
imageView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(5)
make.left.equalToSuperview().offset(5)
make.width.height.equalTo(20)}self.iconImageView = imageView
}
iconImageView?.sd_setImage(url: imageIconURL)
iconImageView?.isHidden = false
} else { / / hide
iconImageView?.isHidden = true}}}Copy the code
Existing problems
Improved code complexity
–View initialization
The logic is placed in place of the binding values, increasing the complexity of updating view methods.An optional value
– Attribute use optional value Unpack optional value is not convenient to use.
Using the Lazy attribute
class UITableView {
private lazy var iconImageView: UIImageView = {
let imageView = UIImageView()
contentView.addSubview(imageView)
imageView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(5)
make.left.equalToSuperview().offset(5)
make.width.height.equalTo(20)}return imageView
}()
func bind(props: CellProps) {
/ / show
if let imageIconURL = props.imageIconURL {
iconImageView.sd_setImage(url: imageIconURL)
iconImageView.isHidden = false
} else { / / hide
iconImageView.isHidden = true // This will be initialized}}}Copy the code
Existing problems
Initialization cannot be avoided
– It is impossible to avoid initializing views when they are not needed, such as for view SettingsisHidden=true
LazyView implementation
The result is a simple LazyView that implements lazy initialization to avoid initialization in scenarios like isHidden, while also handling such scenarios elegantly.
LazyView code implementation
public class LazyView<T> {
private var block: (() -> T)?
public var value: T! {
if wrappedValue = = nil {
wrappedValue = block!()
block = nil
}
return wrappedValue!
}
public private(set) var wrappedValue: T?
public init(_ block: @escaping() - >T) {
self.block = block
}
}
extension LazyView {
@inlinable
func show(_ block: (T) - >Void) {
block(value)
}
@inlinable
func hide(_ block: (T) - >Void) {
if let wrappedValue = wrappedValue {
block(wrappedValue)
}
}
}
Copy the code
Tip: Use @inlinable to prompt the compiler for method inlining optimization.
LazyView code after transformation
class UITableView {
private lazy var iconImageView: LazyView<UIImageView> = LazyView{[unowned self] in
let imageView = UIImageView()
contentView.addSubview(imageView)
imageView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(5)
make.left.equalToSuperview().offset(5)
make.width.height.equalTo(20)}return imageView
}()
func bind(props: CellProps) {
/ / show
if let imageIconURL = props.imageIconURL {
iconImageView.show {
$0.sd_setImage(url: imageIconURL, options: [])
}
} else {
/ / hide
iconImageView.hide { $0.isHidden = true}}}}Copy the code
conclusion
Property Wrapper was initially considered, but the Property Wrapper cannot support lazy properties. It only provides an idea, but the design is not perfect enough. For example, [unowned self] needs to solve the problem of circular reference. I hope it can be optimized later. I also hope you can share some better implementations.