diff --git a/LeadKit/LeadKit.xcodeproj/project.pbxproj b/LeadKit/LeadKit.xcodeproj/project.pbxproj index f2aa7880..28200325 100644 --- a/LeadKit/LeadKit.xcodeproj/project.pbxproj +++ b/LeadKit/LeadKit.xcodeproj/project.pbxproj @@ -8,6 +8,11 @@ /* Begin PBXBuildFile section */ 7830C4151C6B337D00180D02 /* CocoaLumberjack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7830C4141C6B337D00180D02 /* CocoaLumberjack.framework */; }; + 7837F60F1CBCF5C0000D74C1 /* EstimatedViewHeightProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7837F60E1CBCF5C0000D74C1 /* EstimatedViewHeightProtocol.swift */; }; + 786A17A11CB8D71D007F9661 /* UIImage+CapInsetsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 786A17A01CB8D71D007F9661 /* UIImage+CapInsetsUtils.swift */; }; + 787682FA1CAD40C300532AB3 /* StaticEstimatedViewHeightProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787682F91CAD40C200532AB3 /* StaticEstimatedViewHeightProtocol.swift */; }; + 787783631CA03CA0001CDC9B /* NSIndexPath+ImmutableIndexPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787783621CA03CA0001CDC9B /* NSIndexPath+ImmutableIndexPath.swift */; }; + 787783671CA04D4A001CDC9B /* NSString+SizeCalculation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 787783661CA04D4A001CDC9B /* NSString+SizeCalculation.swift */; }; 78A74EA91C6B373700FE9724 /* UIView+DefaultNibName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78A74EA81C6B373700FE9724 /* UIView+DefaultNibName.swift */; }; 78B0FC7D1C6B2BE200358B64 /* LogFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B0FC7C1C6B2BE200358B64 /* LogFormatter.swift */; }; 78B0FC7F1C6B2C4D00358B64 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78B0FC7E1C6B2C4D00358B64 /* Log.swift */; }; @@ -15,7 +20,7 @@ 78CFEE2E1C5C456B00F50370 /* LeadKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 78CFEE2D1C5C456B00F50370 /* LeadKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 78CFEE351C5C456B00F50370 /* LeadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78CFEE2A1C5C456B00F50370 /* LeadKit.framework */; }; 78CFEE3A1C5C456B00F50370 /* LeadKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE391C5C456B00F50370 /* LeadKitTests.swift */; }; - 78CFEE511C5C45E500F50370 /* UIStoryboard+InstantiateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE451C5C45E500F50370 /* UIStoryboard+InstantiateViewController.swift */; }; + 78CFEE511C5C45E500F50370 /* UIStoryboard in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE451C5C45E500F50370 /* UIStoryboard */; }; 78CFEE521C5C45E500F50370 /* UITableView+CellRegistration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE461C5C45E500F50370 /* UITableView+CellRegistration.swift */; }; 78CFEE531C5C45E500F50370 /* UITableView+DequeueCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE471C5C45E500F50370 /* UITableView+DequeueCustomCell.swift */; }; 78CFEE541C5C45E500F50370 /* UIView+LoadFromNib.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE481C5C45E500F50370 /* UIView+LoadFromNib.swift */; }; @@ -27,8 +32,7 @@ 78CFEE5A1C5C45E500F50370 /* ViewHeightProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE4F1C5C45E500F50370 /* ViewHeightProtocol.swift */; }; 78CFEE5B1C5C45E500F50370 /* ViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE501C5C45E500F50370 /* ViewModelProtocol.swift */; }; 78E59B191C773EE600C6BFE9 /* ObjectsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E59B181C773EE600C6BFE9 /* ObjectsGenerator.swift */; }; - 78E59B1B1C77470A00C6BFE9 /* TableViewCellsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E59B1A1C77470A00C6BFE9 /* TableViewCellsGenerator.swift */; }; - 78E59B2A1C7861AF00C6BFE9 /* TableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E59B291C7861AF00C6BFE9 /* TableController.swift */; }; + 78E59B1B1C77470A00C6BFE9 /* ViewsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E59B1A1C77470A00C6BFE9 /* ViewsGenerator.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -43,6 +47,11 @@ /* Begin PBXFileReference section */ 7830C4141C6B337D00180D02 /* CocoaLumberjack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaLumberjack.framework; path = Carthage/Build/iOS/CocoaLumberjack.framework; sourceTree = SOURCE_ROOT; }; + 7837F60E1CBCF5C0000D74C1 /* EstimatedViewHeightProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EstimatedViewHeightProtocol.swift; sourceTree = ""; }; + 786A17A01CB8D71D007F9661 /* UIImage+CapInsetsUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+CapInsetsUtils.swift"; sourceTree = ""; }; + 787682F91CAD40C200532AB3 /* StaticEstimatedViewHeightProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StaticEstimatedViewHeightProtocol.swift; sourceTree = ""; }; + 787783621CA03CA0001CDC9B /* NSIndexPath+ImmutableIndexPath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSIndexPath+ImmutableIndexPath.swift"; sourceTree = ""; }; + 787783661CA04D4A001CDC9B /* NSString+SizeCalculation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSString+SizeCalculation.swift"; sourceTree = ""; }; 78A74EA81C6B373700FE9724 /* UIView+DefaultNibName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+DefaultNibName.swift"; path = "LeadKit/Extensions/UIView/UIView+DefaultNibName.swift"; sourceTree = SOURCE_ROOT; }; 78B0FC7C1C6B2BE200358B64 /* LogFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogFormatter.swift; sourceTree = ""; }; 78B0FC7E1C6B2C4D00358B64 /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; @@ -53,7 +62,7 @@ 78CFEE341C5C456B00F50370 /* LeadKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LeadKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 78CFEE391C5C456B00F50370 /* LeadKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeadKitTests.swift; sourceTree = ""; }; 78CFEE3B1C5C456B00F50370 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 78CFEE451C5C45E500F50370 /* UIStoryboard+InstantiateViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard+InstantiateViewController.swift"; sourceTree = ""; }; + 78CFEE451C5C45E500F50370 /* UIStoryboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = folder; name = UIStoryboard; path = LeadKit/Extensions/UIStoryboard; sourceTree = SOURCE_ROOT; }; 78CFEE461C5C45E500F50370 /* UITableView+CellRegistration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UITableView+CellRegistration.swift"; path = "LeadKit/Extensions/UITableView/UITableView+CellRegistration.swift"; sourceTree = SOURCE_ROOT; }; 78CFEE471C5C45E500F50370 /* UITableView+DequeueCustomCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UITableView+DequeueCustomCell.swift"; path = "LeadKit/Extensions/UITableView/UITableView+DequeueCustomCell.swift"; sourceTree = SOURCE_ROOT; }; 78CFEE481C5C45E500F50370 /* UIView+LoadFromNib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+LoadFromNib.swift"; path = "LeadKit/Extensions/UIView/UIView+LoadFromNib.swift"; sourceTree = SOURCE_ROOT; }; @@ -65,8 +74,7 @@ 78CFEE4F1C5C45E500F50370 /* ViewHeightProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewHeightProtocol.swift; sourceTree = ""; }; 78CFEE501C5C45E500F50370 /* ViewModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewModelProtocol.swift; sourceTree = ""; }; 78E59B181C773EE600C6BFE9 /* ObjectsGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectsGenerator.swift; sourceTree = ""; }; - 78E59B1A1C77470A00C6BFE9 /* TableViewCellsGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCellsGenerator.swift; sourceTree = ""; }; - 78E59B291C7861AF00C6BFE9 /* TableController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableController.swift; sourceTree = ""; }; + 78E59B1A1C77470A00C6BFE9 /* ViewsGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewsGenerator.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -97,10 +105,25 @@ path = Frameworks; sourceTree = ""; }; + 787783611CA03C84001CDC9B /* NSIndexPath */ = { + isa = PBXGroup; + children = ( + 787783621CA03CA0001CDC9B /* NSIndexPath+ImmutableIndexPath.swift */, + ); + path = NSIndexPath; + sourceTree = ""; + }; + 787783651CA04D14001CDC9B /* NSString */ = { + isa = PBXGroup; + children = ( + 787783661CA04D4A001CDC9B /* NSString+SizeCalculation.swift */, + ); + path = NSString; + sourceTree = ""; + }; 78A74EAA1C6B401800FE9724 /* Classes */ = { isa = PBXGroup; children = ( - 78E59B281C78613B00C6BFE9 /* TableView */, 78E59B171C773E9600C6BFE9 /* Cache */, 78B0FC7B1C6B2BAE00358B64 /* Logging */, ); @@ -160,9 +183,12 @@ 78CFEE441C5C45E500F50370 /* Extensions */ = { isa = PBXGroup; children = ( + 787783651CA04D14001CDC9B /* NSString */, + 787783611CA03C84001CDC9B /* NSIndexPath */, 78E59B2C1C786CD500C6BFE9 /* UIView */, 78E59B2B1C786CBF00C6BFE9 /* UITableView */, - 78CFEE451C5C45E500F50370 /* UIStoryboard+InstantiateViewController.swift */, + C37210711ACDF1042F70C2EB /* UIImage */, + C372153938A7B7D327F55124 /* UIStoryboard */, ); path = Extensions; sourceTree = ""; @@ -177,6 +203,8 @@ 78CFEE4D1C5C45E500F50370 /* StaticViewHeightProtocol.swift */, 78CFEE4F1C5C45E500F50370 /* ViewHeightProtocol.swift */, 78CFEE501C5C45E500F50370 /* ViewModelProtocol.swift */, + 787682F91CAD40C200532AB3 /* StaticEstimatedViewHeightProtocol.swift */, + 7837F60E1CBCF5C0000D74C1 /* EstimatedViewHeightProtocol.swift */, ); path = Protocols; sourceTree = ""; @@ -185,19 +213,11 @@ isa = PBXGroup; children = ( 78E59B181C773EE600C6BFE9 /* ObjectsGenerator.swift */, - 78E59B1A1C77470A00C6BFE9 /* TableViewCellsGenerator.swift */, + 78E59B1A1C77470A00C6BFE9 /* ViewsGenerator.swift */, ); path = Cache; sourceTree = ""; }; - 78E59B281C78613B00C6BFE9 /* TableView */ = { - isa = PBXGroup; - children = ( - 78E59B291C7861AF00C6BFE9 /* TableController.swift */, - ); - path = TableView; - sourceTree = ""; - }; 78E59B2B1C786CBF00C6BFE9 /* UITableView */ = { isa = PBXGroup; children = ( @@ -216,6 +236,22 @@ path = UIView; sourceTree = ""; }; + C37210711ACDF1042F70C2EB /* UIImage */ = { + isa = PBXGroup; + children = ( + 786A17A01CB8D71D007F9661 /* UIImage+CapInsetsUtils.swift */, + ); + path = UIImage; + sourceTree = ""; + }; + C372153938A7B7D327F55124 /* UIStoryboard */ = { + isa = PBXGroup; + children = ( + 78CFEE451C5C45E500F50370 /* UIStoryboard */, + ); + path = UIStoryboard; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -373,22 +409,26 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7837F60F1CBCF5C0000D74C1 /* EstimatedViewHeightProtocol.swift in Sources */, 78CFEE541C5C45E500F50370 /* UIView+LoadFromNib.swift in Sources */, 78CFEE521C5C45E500F50370 /* UITableView+CellRegistration.swift in Sources */, 78B0FC7F1C6B2C4D00358B64 /* Log.swift in Sources */, 78CFEE571C5C45E500F50370 /* StaticNibNameProtocol.swift in Sources */, + 787783671CA04D4A001CDC9B /* NSString+SizeCalculation.swift in Sources */, 78CFEE531C5C45E500F50370 /* UITableView+DequeueCustomCell.swift in Sources */, - 78E59B1B1C77470A00C6BFE9 /* TableViewCellsGenerator.swift in Sources */, + 78E59B1B1C77470A00C6BFE9 /* ViewsGenerator.swift in Sources */, 78B0FC811C6B2CD500358B64 /* App.swift in Sources */, - 78E59B2A1C7861AF00C6BFE9 /* TableController.swift in Sources */, 78CFEE551C5C45E500F50370 /* NibNameProtocol.swift in Sources */, - 78CFEE511C5C45E500F50370 /* UIStoryboard+InstantiateViewController.swift in Sources */, + 78CFEE511C5C45E500F50370 /* UIStoryboard in Sources */, 78CFEE561C5C45E500F50370 /* ReuseIdentifierProtocol.swift in Sources */, 78E59B191C773EE600C6BFE9 /* ObjectsGenerator.swift in Sources */, 78CFEE5B1C5C45E500F50370 /* ViewModelProtocol.swift in Sources */, 78CFEE5A1C5C45E500F50370 /* ViewHeightProtocol.swift in Sources */, + 787682FA1CAD40C300532AB3 /* StaticEstimatedViewHeightProtocol.swift in Sources */, 78A74EA91C6B373700FE9724 /* UIView+DefaultNibName.swift in Sources */, + 786A17A11CB8D71D007F9661 /* UIImage+CapInsetsUtils.swift in Sources */, 78CFEE581C5C45E500F50370 /* StaticViewHeightProtocol.swift in Sources */, + 787783631CA03CA0001CDC9B /* NSIndexPath+ImmutableIndexPath.swift in Sources */, 78CFEE591C5C45E500F50370 /* StoryboardIdentifierProtocol.swift in Sources */, 78B0FC7D1C6B2BE200358B64 /* LogFormatter.swift in Sources */, ); diff --git a/LeadKit/LeadKit/Classes/Cache/TableViewCellsGenerator.swift b/LeadKit/LeadKit/Classes/Cache/TableViewCellsGenerator.swift deleted file mode 100644 index 0cb437f7..00000000 --- a/LeadKit/LeadKit/Classes/Cache/TableViewCellsGenerator.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// TableViewCellsPool.swift -// LeadKit -// -// Created by Иван Смолин on 19/02/16. -// Copyright © 2016 Touch Instinct. All rights reserved. -// - -import Foundation - -/// class that generates table view cells on initialization phase and then return its when necessary -public class TableViewCellsGenerator: ObjectsGenerator { - /** - initializer function - - - parameter poolSize: number of cells to generate - - parameter cellNibName: cell nib name - - - returns: nothing - */ - init(poolSize: UInt, cellNibName: String) { - super.init(poolSize: poolSize, objectsContructor: {() -> T in - T.loadFromNib(named: cellNibName) - }) - } -} diff --git a/LeadKit/LeadKit/Classes/Cache/ViewsGenerator.swift b/LeadKit/LeadKit/Classes/Cache/ViewsGenerator.swift new file mode 100644 index 00000000..8d1de582 --- /dev/null +++ b/LeadKit/LeadKit/Classes/Cache/ViewsGenerator.swift @@ -0,0 +1,27 @@ +// +// TableViewCellsPool.swift +// LeadKit +// +// Created by Иван Смолин on 19/02/16. +// Copyright © 2016 Touch Instinct. All rights reserved. +// + +import Foundation + +/// class that generates views on initialization phase and then return its when necessary +public class ViewsGenerator: ObjectsGenerator { + /** + initializer function + + - parameter poolSize: number of cells to generate + - parameter nibName: view nib name + + - returns: nothing + */ + init(poolSize: UInt, nibName: String) { + super.init(poolSize: poolSize, objectsContructor: {() -> T in + T.loadFromNib(named: nibName) + }) + } + +} diff --git a/LeadKit/LeadKit/Classes/TableView/TableController.swift b/LeadKit/LeadKit/Classes/TableView/TableController.swift deleted file mode 100644 index 61b64558..00000000 --- a/LeadKit/LeadKit/Classes/TableView/TableController.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// TableViewController.swift -// LeadKit -// -// Created by Иван Смолин on 20/02/16. -// Copyright © 2016 Touch Instinct. All rights reserved. -// - -import UIKit - -/// abstract class which holds few behaviour configuration properties, -/// inherit and add conformance for table view data source and delegate protocols -public class TableController: NSObject, UITableViewDataSource, UITableViewDelegate { - - /** - enumeration which describes how to calculate and store view models for cells - - - Precalculated: precacalculate view models for all cells and keep it in memory - - OnTheFlight: calculate view models when needed and forget it immideatelly - - OnTheFlightWithCache: calculate view models when needed and cache it - */ - internal enum TableControllerViewModelCalculationType { - case Precalculated - case OnTheFlight - case OnTheFlightWithCache - } - - /** - enumeration which describes how to create cells - - - Preloaded: load some amount of cells before data source delegate calls - - OnTheFlight: let table view deside when to load cells - */ - internal enum TableControllerCellCreationType { - case Preloaded - case OnTheFlight - } - - internal let viewModelCalculationType: TableControllerViewModelCalculationType - - internal let cellCreationType: TableControllerCellCreationType - - internal init(viewModelCalculationType calculationType: TableControllerViewModelCalculationType = .OnTheFlight, - cellCreationType creationType: TableControllerCellCreationType = .OnTheFlight) { - self.viewModelCalculationType = calculationType - self.cellCreationType = creationType - - super.init() - } - - public func numberOfSectionsInTableView(tableView: UITableView) -> Int { - preconditionFailure("subclass should implement \(__FUNCTION__)") - } - - public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - preconditionFailure("subclass should implement \(__FUNCTION__)") - } - - public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - preconditionFailure("subclass should implement \(__FUNCTION__)") - } - -} diff --git a/LeadKit/LeadKit/Extensions/NSIndexPath/NSIndexPath+ImmutableIndexPath.swift b/LeadKit/LeadKit/Extensions/NSIndexPath/NSIndexPath+ImmutableIndexPath.swift new file mode 100644 index 00000000..6df07654 --- /dev/null +++ b/LeadKit/LeadKit/Extensions/NSIndexPath/NSIndexPath+ImmutableIndexPath.swift @@ -0,0 +1,28 @@ +// +// NSIndexPath+ImmutableIndexPath.swift +// LeadKit +// +// Created by Иван Смолин on 21/03/16. +// Copyright © 2016 Touch Instinct. All rights reserved. +// + +import Foundation + +// http://stackoverflow.com/a/21686163 + +extension NSIndexPath { + /** + method which check instance class and create immutable copy if class is not NSIndexPath + + - returns: immutable NSIndexPath instance + */ + + func immutableIndexPath() -> NSIndexPath { + if Mirror(reflecting: self).subjectType == NSIndexPath.self { // check for UIMutableIndexPath + return self + } + + return NSIndexPath(forItem: self.item, inSection: self.section) + } + +} diff --git a/LeadKit/LeadKit/Extensions/NSString/NSString+SizeCalculation.swift b/LeadKit/LeadKit/Extensions/NSString/NSString+SizeCalculation.swift new file mode 100644 index 00000000..f6d35a93 --- /dev/null +++ b/LeadKit/LeadKit/Extensions/NSString/NSString+SizeCalculation.swift @@ -0,0 +1,81 @@ +// +// NSString+SizeCAlculation.swift +// LeadKit +// +// Created by Иван Смолин on 21/03/16. +// Copyright © 2016 Touch Instinct. All rights reserved. +// + +import Foundation + +/** + rounds double value 1.7800000004 to 1.78 + + - parameter val: value for rounding + - parameter persicion: important number of digits after comma + + - returns: rounded value + */ +private func roundDouble(val: Double, withPersicion persicion: UInt) -> Double { + let divider = pow(10.0, Double(persicion - 1)) + + return round(val * divider) / divider +} + +extension NSString { + + /** + method which calculates string height based on given width and character attributes + + - parameter width: maximum width of string + - parameter attributes: dictionary with string character attributes + + - returns: string height + */ + public func heightWith(width: CGFloat, attributes: [String: AnyObject]?) -> CGFloat { + return self.boundingRectWithSize(CGSize(width: width, height: CGFloat.max), + options: .UsesLineFragmentOrigin, + attributes: attributes, + context: nil).size.height + } + + /** + method which calculates required number of lines to fit string with given width and character attributes + + - parameter width: maximum width of string + - parameter attributes: dictionary with string character attributes + + - returns: minimum number of lines + */ + func numberOfLinesWith(width: CGFloat, attributes: [String: AnyObject]) -> UInt { + guard let font = attributes[NSFontAttributeName] as? UIFont else { + preconditionFailure("Value for NSFontAttributeName should be defined in attributes") + } + + let paragraphStyle = attributes[NSParagraphStyleAttributeName] as? NSParagraphStyle + + let lineHeight = font.lineHeight * (paragraphStyle?.lineHeightMultiple ?? 1.0) + + let lineHeightRounded = roundDouble(Double(lineHeight), withPersicion: 2) + + let height = heightWith(width, attributes: attributes) + + let heightRounded = roundDouble(Double(height), withPersicion: 2) + + let numberOfLines = ceil(heightRounded / lineHeightRounded) + + return UInt(numberOfLines) + } + + /** + method which calculates string width based on given character attributes + + - parameter attriutes: dictionary with string character attributes + + - returns: string width + */ + public func widthWith(attriutes: [String: AnyObject]) -> CGFloat { + return CGFloat(ceil(Double(sizeWithAttributes(attriutes).width))) + } + +} diff --git a/LeadKit/LeadKit/Extensions/UIImage/UIImage+CapInsetsUtils.swift b/LeadKit/LeadKit/Extensions/UIImage/UIImage+CapInsetsUtils.swift new file mode 100644 index 00000000..be8dfbed --- /dev/null +++ b/LeadKit/LeadKit/Extensions/UIImage/UIImage+CapInsetsUtils.swift @@ -0,0 +1,90 @@ +// +// UIImage+CapInsetsUtils.swift +// LeadKit +// +// Created by Иван Смолин on 09/04/16. +// Copyright © 2016 Touch Instinct. All rights reserved. +// + +import UIKit + +extension UIImage { + + /** + method which render current UIImage for specific size and return new UIImage + + - parameter size: size of new rendered image + + - returns: new rendered UIImage + */ + public func renderWithSize(size: CGSize) -> UIImage { + UIGraphicsBeginImageContextWithOptions(size, false, 0.0) + + self.drawInRect(CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)) + + let resizedImage = UIGraphicsGetImageFromCurrentImageContext() + + UIGraphicsEndImageContext() + + return resizedImage + } + + /** + this method tries to find requested image with specific parameters in cache, and if doesn't exists - create it + + - parameter name: name of the image used in UIImage(named:) + - parameter size: size of rendered image + - parameter capInsets: cap insets for image + - parameter cache: cache to search + + - returns: cached or newly created image or nil if no such image find with specified name + */ + public static func fetchOrCreateImageWithName(name: String, + size: CGSize, + capInsets: UIEdgeInsets, + cache: NSCache) -> UIImage? { + let cacheKey = "\(name)-\(NSStringFromUIEdgeInsets(capInsets))-\(NSStringFromCGSize(size))" + + if let cachedImage = cache.objectForKey(cacheKey) as? UIImage { + return cachedImage + } + + if let renderedImage = UIImage(named: name)?.resizableImageWithCapInsets(capInsets).renderWithSize(size) { + cache.setObject(renderedImage, forKey: cacheKey) + + return renderedImage + } + + return nil + } + + /** + this metho tries to find requested image with specific parameters in cache, and if doesn't exists - create it + + - parameter name: name of the image used in UIImage(named:) + - parameter size: size of rendered image + - parameter assetsInsetsForScales: mapping of screen scale to UIEdgeInsets which defined in XCAssets + - parameter cache: cache to search + + - returns: cached or newly created image or nil if no such image find with specified name + */ + public static func fetchOrCreateImageWithName(name: String, + size: CGSize, + assetsInsetsForScales: [CGFloat: UIEdgeInsets], + cache: NSCache) -> UIImage? { + let scale = UIScreen.mainScreen().scale + + if let assetsInsetsForScale = assetsInsetsForScales[scale] { + let capInsetsForScale = UIEdgeInsets(top: assetsInsetsForScale.top / scale, + left: assetsInsetsForScale.left / scale, + bottom: assetsInsetsForScale.bottom / scale, + right: assetsInsetsForScale.right / scale) + + + return self.fetchOrCreateImageWithName(name, size: size, capInsets: capInsetsForScale, cache: cache) + } + + return nil + } + +} diff --git a/LeadKit/LeadKit/Extensions/UIStoryboard+InstantiateViewController.swift b/LeadKit/LeadKit/Extensions/UIStoryboard/UIStoryboard+InstantiateViewController.swift similarity index 100% rename from LeadKit/LeadKit/Extensions/UIStoryboard+InstantiateViewController.swift rename to LeadKit/LeadKit/Extensions/UIStoryboard/UIStoryboard+InstantiateViewController.swift diff --git a/LeadKit/LeadKit/Protocols/EstimatedViewHeightProtocol.swift b/LeadKit/LeadKit/Protocols/EstimatedViewHeightProtocol.swift new file mode 100644 index 00000000..be455230 --- /dev/null +++ b/LeadKit/LeadKit/Protocols/EstimatedViewHeightProtocol.swift @@ -0,0 +1,25 @@ +// +// EstimatedViewheightProtocol.swift +// LeadKit +// +// Created by Иван Смолин on 12/04/16. +// Copyright © 2016 Touch Instinct. All rights reserved. +// + +import Foundation + +/** + * protocol which ensures that specific type can return estimated height of view for view model + */ +public protocol EstimatedViewHeightProtocol { + associatedtype ViewModelType + + /** + method which returns estimated view height for specific view model + + - parameter viewModel: object which represents view model of view + + - returns: estimatedViewHeight view height + */ + static func estimatedViewHeight(forViewModel viewModel: ViewModelType) -> CGFloat +} \ No newline at end of file diff --git a/LeadKit/LeadKit/Protocols/StaticEstimatedViewHeightProtocol.swift b/LeadKit/LeadKit/Protocols/StaticEstimatedViewHeightProtocol.swift new file mode 100644 index 00000000..14ba4467 --- /dev/null +++ b/LeadKit/LeadKit/Protocols/StaticEstimatedViewHeightProtocol.swift @@ -0,0 +1,21 @@ +// +// StaticEstimatedViewheightProtocol.swift +// LeadKit +// +// Created by Иван Смолин on 31/03/16. +// Copyright © 2016 Touch Instinct. All rights reserved. +// + +import Foundation + +/** + * protocol which ensures that specific type can return estimated height of view + */ +public protocol StaticEstimatedViewHeightProtocol { + /** + method which return estimated view height + + - returns: estimated view height + */ + static func estimatedViewHeight() -> CGFloat +}