AirJD 焦点
AirJD

没有录音文件
00:00/00:00
加收藏

当泛型遇上协议(Swift&iOS) by 蓝晨钰@猿题库

发布者 mobile
发布于 1470270288638  浏览 6005 关键词 移动开发, iOS 
分享到

第1页

Generic Programming with Protocol in Swift iOS



第2页

Generic Programming with Protocol in Swift iOS



第4页

func swapInt(inout a: Int, inout _ b: Int) { let tmp = a a=b b = tmp

} var someInt = 1 var anotherInt = 5 swapInt(&someInt, &anotherInt)

func swapString(inout a: String, inout _ b: String) { let tmp = a a=b b = tmp

}



第5页

func swapValue<T>(inout a: T, inout _ b: T) { let tmp = a a=b b = tmp

}

var someInt = 1 var anotherInt = 5 var someString = "some" var anotherString = "another" swapValue(&someInt, &anotherInt) swapValue(&someString, &anotherString)



第8页

// ? Optional var optInt: Int? var optInt2: Optional<Int>

public enum Optional<Wrapped> : … { case None case Some(Wrapped) …

}



第9页

enum FailableData<T> { case Error(Error) case Data(T)

}



completion FailableData<Exercise>



dataController.requestOrCreateExerciseWithTopicTask



(task, completion: { data in



switch data {



case .Data(let exercise):



// exercise



Exercise



case .Error(let error):



// Error



}



})



第11页

JSONSerializable

public protocol JSONSerializable { func toJSONObject() -> JSONObject

} class Man: JSONSerializable {

var name: String? var son: Man? func toJSONObject() -> JSONObject {

var json = JSONDictionary() name --> json["name"] son --> json["son"] return json } } man.toJSONObject()



第12页

struct Serialization { static func convertAndAssign<T: JSONSerializable>(property: T?,

inout toJSONObject jsonObject: JSONObject?) -> JSONObject? { if let property = property { jsonObject = property.toJSONObject() } return jsonObject

} } infix operator --> { associativity right precedence 150 } public func --> <T: JSONSerializable>(property: T?, inout jsonObject: JSONObject?) -> JSONObject? {

return Serialization.convertAndAssign(property, toJSONObject: &jsonObject) }

extension String: JSONSerializable { public func toJSONObject() -> JSONObject { return self }

}



CaesarParser



https://github.com/lancy/CaesarParser



第14页

GenericViewWrapper



• ViewWrapper contentView subview

• contentView UIView

• ViewWrapper contentView

• contentView



Wrapper Content



第15页

class GenericViewWrapper<ContentView: UIView>: UIView { /// The configurator type typealias Configurator = (config: GenericViewWrapper<ContentView>)

-> () /// Vertical alignment var verticalAlignment: AlignmentMode = .Fill /// Horizontal alignment var horizontalAlignment: AlignmentMode = .Fill /// The content view var contentView: ContentView /// Init init(contentView: ContentView, configurator: Configurator? = nil) { self.contentView = contentView super.init(frame: CGRectZero) configurator?(config: self) setupUserInterface() } // implementation …

}



第16页

labelWrapper padding



15pt



lazy var labelWrapper: GenericViewWrapper<UILabel> = { let label = UILabel() label.text = "Label" label.font = UIFont.systemFontOfSize(12) let wrapper = GenericViewWrapper(contentView: label) { config in config.horizontalAlignment = .LeadingPadding(15) config.verticalAlignment = .Center } return wrapper

}()



labelWrapper UILabel

labelWrapper.contentView.text = "Text"



第18页

ViewWrapper

class GenericTouchableViewWrapper<ContentView: UIView>: GenericViewWrapper<ContentView> {

private let target: AnyObject private let action: Selector /// Create and return a touchable view wrapper that wrap `contentView` and send `action` to `target` while user touch up inside the wrapper view. Can be config with `configurator`. init(contentView: ContentView, target: AnyObject, action: Selector, configurator: Configurator? = nil) {

self.target = target self.action = action super.init(contentView: contentView, configurator: configurator) } // Handle touch event and send action to target… }



第19页

// ScrollViewWrapper



ContentView



class GenericScrollableViewWrapper<ContentView: UIView>: UIScrollView



//



item



StackLayoutView



class GenericStackLayoutView<ArrangedView: UIView>: UIView



第21页

?



第23页



• SectionView • SectionView

HeaderView ItemView



第24页

• ItemView View

• SectionHeaderView View

• ItemView SectionHeaderView ViewModel



第25页

ViewModel

func makeViewModel(paper: Paper) -> ViewModel { let sectionViewModels = paper.chapters.map { chapter in let headerViewModel = HeaderViewModel(chapter) let itemViewModels = chapter.questions.map { question in return ItemViewModel(question) } return SectionViewModel(headerViewModel, itemViewModels) } return ViewModel(sectionViewModels)

} let cardView = CardView(viewModel: makeViewModel())



第26页

ViewModel

/// Able to be created with default initializer protocol Creatable {

/// Default initializer /// /// - returns: Created instance init() } /// Support view model protocol ViewModeled: class { /// View model type associatedtype ViewModel func bindDataWithViewModel(viewModel: ViewModel) }

/// Both Creatable and ViewModeled typealias CreatableViewModeled = protocol<Creatable, ViewModeled>



第27页

StaticSize StaticHeight

/// Size is constant protocol StaticSize: StaticHeight, StaticWidth {

/// Static height static var staticSize: CGSize { get } }



第29页

Protocol



ViewModelClass



ViewClass



GenericCard ViewModelType

GenericCard SectionViewModelType



GenericCard ViewModel

GenericCard SectionViewModel

SectionHeader ViewModel



GenericCard View

GenericCard SectionView

SectionHeader View

GenericCard SectionContentView



ItemViewModel



ItemView



Generic Generic



第30页

GenericCard ViewModelType

protocol GenericCardViewModelType: class { associatedtype SectionViewModelType: GenericCardSectionViewModelType var sectionViewModels: [SectionViewModelType] { get set }

}

GenericCard SectionViewModelType

protocol GenericCardSectionViewModelType: class { associatedtype ItemViewType: UIView, CreatableViewModeled, StaticSize associatedtype SectionHeaderViewType: UIView, CreatableViewModeled,

StaticHeight var itemViewModels: [ItemViewType.ViewModel] { get set } var sectionHeaderViewModel: SectionHeaderViewType.ViewModel? { get

set } }



第31页

ViewModel

GenericCard ViewModel

class GenericCardViewModel<SectionViewModelType: GenericCardSectionViewModelType>: GenericCardViewModelType {

var sectionViewModels: [SectionViewModelType] init(sectionViewModels: [SectionViewModelType]) {

self.sectionViewModels = sectionViewModels }

}



第32页

GenericCard SectionViewModel

class GenericCardSectionViewModel <ItemViewType: UIView, SectionHeaderViewType: UIView where ItemViewType: protocol<CreatableViewModeled, StaticSize>, SectionHeaderViewType: protocol<CreatableViewModeled, StaticHeight> > : GenericCardSectionViewModelType { var itemViewModels: [ItemViewType.ViewModel] var sectionHeaderViewModel: SectionHeaderViewType.ViewModel? init(itemViewModels: [ItemViewType.ViewModel], sectionHeaderViewModel:

SectionHeaderViewType.ViewModel? = nil) { self.itemViewModels = itemViewModels self.sectionHeaderViewModel = sectionHeaderViewModel

} }



第33页

GenericCard View

final class GenericCardView<ViewModelType: GenericCardViewModelType> : UIView {

weak var delegate: GenericCardViewDelegate?

init(viewModel: ViewModelType) { super.init(frame: CGRect.zero) var subviews = [UIView]() for (index, svm) in viewModel.sectionViewModels.enumerate() { let sectionView =

GenericCardSectionView<ViewModelType.SectionViewModelType>(viewModel: svm, delegate: self, index: index)

subviews.append(sectionView) } let list = StackLayoutView(arrangedSubviews: subviews) addSubview(list) LayoutUtils.setEdgesFor(list)

}

}



第34页

final class GenericCardSectionView<ViewModelType: GenericCardSectionViewModelType>: UIView {



GenericCard



typealias ItemViewType = ViewModelType.ItemViewType



SectionView



typealias SectionHeaderViewType = ViewModelType.SectionHeaderViewType



init(viewModel: ViewModelType, delegate: GenericCardSectionContentViewDelegate, index: Int) {

super.init(frame: CGRectZero) var subviews = [UIView]()



if let headerViewModel = viewModel.sectionHeaderViewModel {



let headerView = SectionHeaderViewType()



headerView.bindDataWithViewModel(headerViewModel)



SectionHeader



LayoutUtils.setHeightFor(headerView, height: SectionHeaderViewType.staticHeight)



View



subviews.append(headerView)



}



let contentView = GenericCardSectionContentView<ItemViewType>(itemViewModels: viewModel.itemViewModels)

contentView.delegate = delegate contentView.tag = index subviews.append(contentView)



GenericCard SectionContentView



let list = StackLayoutView(arrangedSubviews: subviews) addSubview(list) LayoutUtils.setEdgesFor(list) }



}



第35页

GenericCard SectionContentView

final class GenericCardSectionContentView<ItemViewType: UIView where ItemViewType: protocol<CreatableViewModeled, StaticSize>>: UIView {

weak var delegate: GenericCardSectionContentViewDelegate? typealias ItemViewModel = ItemViewType.ViewModel private let itemViewModels: [ItemViewModel] init(itemViewModels: [ItemViewModel]) {

self.itemViewModels = itemViewModels super.init(frame: CGRect.zero) setupUserInterface() } }



第36页

private func setupUserInterface() {

let list = itemViewModels.split(step:5).map { vmsSlice in

Array(vmsSlice).map { vm in let itemView = ItemViewType() itemView.bindDataWithViewModel(vm) itemView.tag == index index += 1 return itemView.touchableWrapped(self, action:

#selector(itemViewPressed)) } .stackLayoutWrapped { config in config.axis = .Horizontal config.alongAlignment = .Fill config.distribution = .EqualSpacing } } .stackLayoutWrapped()

addSubview(list) LayoutUtils.setEdgesFor(list)

}



第37页

@objc private func itemViewPressed(view: UIView) { delegate?.cardSectionContentView(self, didTapItemAtIndex: view.tag)

}

protocol GenericCardSectionContentViewDelegate: class { func cardSectionContentView<ContentViewType: UIView>(contentView:

ContentViewType, didTapItemAtIndex index: Int) }

objc UIView



第38页

protocol GenericCardViewDelegate: class { func cardView<CardViewType: UIView>(contentView: CardViewType,

didTapItemAtIndexPath indexPath: NSIndexPath) }

extension GenericCardView: GenericCardSectionContentViewDelegate { func cardSectionContentView<T: UIView>(contentView: T,

didTapItemAtIndex index: Int) { let indexPath = NSIndexPath(forRow: index, inSection:

contentView.tag) delegate?.cardView(self, didTapItemAtIndexPath: indexPath)

} }



第40页

ItemView HeaderView

final class DemoCardItemView: UIView, CreatableViewModeled, StaticSize {

init() {……} static var staticSize: CGSize = CGSize(width: 66, height: 66) struct ViewModel {

let text: String let textColor: UIColor let image: UIImage } func bindDataWithViewModel(viewModel: ViewModel) { label.text = viewModel.text label.textColor = viewModel.textColor imageView.image = viewModel.image } …… } final class DemoCardChapterView: LabelWrapper, CreatableViewModeled, StaticHeight { …… }



第41页

ViewModel

typealias DemoCardSectionViewModel = GenericCardSectionViewModel<DemoCardItemView, DemoCardChapterView> typealias DemoCardViewModel = GenericCardViewModel<DemoCardSectionViewModel>

typealias DemoCardView = GenericCardView<DemoCardViewModel>

func makeViewModel(data: …) -> DemoCardViewModel { // viewModel

}



第42页

let cardView = DemoCardView(viewModel: makeViewModel()) cardView.delegate = self let scrollableCardView = cardView.scrollableWrapped() view.addSubview(scrollableCardView)



第43页

• GenericCardView ItemView HeaderView



• ItemView HeaderView



ViewModel



CardViewModel



• CardViewModel CardView



第45页

One More Thing



第46页

GenericTableViewModeled GenericCollectionViewModeled



第47页

delegate dataSource



/// Generic collection view modeled. protocol GenericCollectionViewModeled: ViewModeled {

/// View model type. associatedtype ViewModel: GenericCollectionViewModelType /// Collection view model. var viewModel: ViewModel? { get set } /// Cell identifier, for generating and getting cell. var cellIdentifier: String { get } /// Collection view. var collectionView: UICollectionView { get } /// Return number of sections from view model func numberOfSections() -> Int /// Return number of items in a `section` from view model func numberOfItemsInSection(section: Int) -> Int /// Return section view model in given `section` func sectionViewModelInSection(section: Int) -> ViewModel.SectionViewModel? /// Return cell view model at `indexPath` func cellViewModelAtIndexPath(indexPath: NSIndexPath) -> ViewModel.SectionViewModel.CellView.ViewModel? /// Delete cell view model at `indexPath` func deleteCellViewModelAtIndexPath(indexPath: NSIndexPath) -> Bool /// Generate/get cell at `indexPath` func dequeueReusableCellAndBindDataForIndexPath(indexPath: NSIndexPath) -> GenericCollectionCell<ViewModel.SectionViewModel.CellView>



extension GenericCollectionViewModeled { /// Default cell identifier var cellIdentifier: String { return "CellIdentifier" } /// Default implementation of binding data with view mo /// /// - parameter viewModel: The view model func bindDataWithViewModel(viewModel: ViewModel) { self.viewModel = viewModel collectionView.reloadData() } /// Default implementation of getting section number fo func numberOfSections() -> Int { return viewModel?.sectionViewModels.count jQuery11020567391887579428_1470270313711 0 } /// Default implementation of getting items number for func numberOfItemsInSection(section: Int) -> Int { return viewModel?.sectionViewModels.elementAtIndex(s } /// Default implementation of getting section view mode func sectionViewModelInSection(section: Int) -> ViewMode return viewModel?.sectionViewModels.elementAtIndex(s } /// Default implementation of getting cell view model f func cellViewModelAtIndexPath(indexPath: NSIndexPath) -> return viewModel?.sectionViewModels.elementAtIndex(i .cellViewModels.elementAtIndex(inde }



第48页

CellViewType HeaderViewType, FooterViewType

final class AnswerCardView: CollectionViewContainer, GenericCollectionViewModeled {

typealias CellView = ItemView typealias SectionHeaderView = ChapterView typealias ViewModel = GenericSectionGroupViewModel<GenericSectionViewModel<CellView, SectionHeaderView, VoidView>> … }



第49页

View

extension GenericCollectionViewModeled where ViewModel.SectionViewModel.CellView: StaticSize {

/// Static item size var staticItemSize: CGSize {

return ViewModel.SectionViewModel.CellView.staticSize } /// Return size for item at 'indexPath'. func sizeForItemAtIndexPath(indexPath: NSIndexPath) -> CGSize {

return staticItemSize } } extension GenericCollectionViewModeled where ViewModel.SectionViewModel.CellView: ViewModeledSize { /// Return size for item at 'indexPath'. func sizeForItemAtIndexPath(indexPath: NSIndexPath) -> CGSize {

guard let cvm = cellViewModelAtIndexPath(indexPath) else { return CGSize.zero }

return ViewModel.SectionViewModel.CellView.sizeWithViewModel(cvm) } }



第51页

Thanks Q&A

We’re Hiring! lancy@fenbi.com



支持文件格式:*.pdf
上传最后阶段需要进行在线转换,可能需要1~2分钟,请耐心等待。