Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance improvement with cell reuse #100

Merged
merged 16 commits into from
Oct 15, 2018
Merged
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.0
4.2
7 changes: 5 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
language: swift
osx_image: xcode9.4
osx_image: xcode10

script:
xcodebuild -workspace CollectionKit.xcworkspace -scheme CollectionKit -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=10.3.1' build test
xcodebuild -workspace CollectionKit.xcworkspace -scheme CollectionKit -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone XR,OS=12.0' build test

before_install:
- pod repo update

after_success:
- bash <(curl -s https://codecov.io/bash) -J 'CollectionKit'
4 changes: 2 additions & 2 deletions CollectionKit.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "CollectionKit"
s.version = "2.1.0"
s.version = "2.2.0"
s.summary = "A modern swift framework for building data-driven reusable collection view components."

s.description = <<-DESC
Expand Down Expand Up @@ -39,7 +39,7 @@ Pod::Spec.new do |s|

s.subspec 'WobbleAnimator' do |cs|
cs.dependency 'CollectionKit/Core'
cs.dependency 'YetAnotherAnimationLibrary'
cs.dependency 'YetAnotherAnimationLibrary', "~> 1.3.0"
cs.source_files = 'WobbleAnimator/**/*.swift'
end
end
4 changes: 2 additions & 2 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ use_frameworks!

target "CollectionKitTests" do

pod 'Quick', "= 1.3.0"
pod 'Nimble', "= 7.1.1"
pod 'Quick', "= 1.3.2"
pod 'Nimble', "= 7.3.1"
end
14 changes: 7 additions & 7 deletions Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
PODS:
- Nimble (7.1.1)
- Quick (1.3.0)
- Nimble (7.3.1)
- Quick (1.3.2)

DEPENDENCIES:
- Nimble (= 7.1.1)
- Quick (= 1.3.0)
- Nimble (= 7.3.1)
- Quick (= 1.3.2)

SPEC REPOS:
https://github.com/cocoapods/specs.git:
- Nimble
- Quick

SPEC CHECKSUMS:
Nimble: 391f07782af4b37914f9bd7b2ffbb952731b8202
Quick: 03278013f71aa05fe9ecabc94fbcc6835f1ee76f
Nimble: 04f732da099ea4d153122aec8c2a88fd0c7219ae
Quick: 2623cb30d7a7f41ca62f684f679586558f483d46

PODFILE CHECKSUM: f33c8746ebf721eac77bc6829bdd94f9e3b0de44
PODFILE CHECKSUM: 056648a7e76b878641ac9a9fd2b13117bd03b5db

COCOAPODS: 1.5.3
7 changes: 5 additions & 2 deletions Sources/Extensions/UIView+CollectionKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ extension UIView {
}

public func recycleForCollectionKitReuse() {
removeFromSuperview()
reuseManager?.queue(view: self)
if let reuseManager = reuseManager {
reuseManager.queue(view: self)
} else {
removeFromSuperview()
}
}
}
2 changes: 1 addition & 1 deletion Sources/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.1.0</string>
<string>2.2.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
Expand Down
45 changes: 33 additions & 12 deletions Sources/Other/CollectionReuseViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,39 @@ public protocol CollectionViewReusableView: class {
}

public class CollectionReuseViewManager: NSObject {

/// Time it takes for CollectionReuseViewManager to
/// dump all reusableViews to save memory
public var lifeSpan: TimeInterval = 5.0

/// When `removeFromCollectionViewWhenReuse` is enabled,
/// cells will always be removed from Collection View during reuse.
/// This is slower but it doesn't influence the `isHidden` property
/// of individual cells.
public var removeFromCollectionViewWhenReuse = false

var reusableViews: [String: [UIView]] = [:]
var cleanupTimer: Timer?
public var lifeSpan: TimeInterval = 0.5

public func queue(view: UIView) {
let identifier = NSStringFromClass(type(of: view))
view.reuseManager = nil
if removeFromCollectionViewWhenReuse {
view.removeFromSuperview()
} else {
view.isHidden = true
}
if reusableViews[identifier] != nil && !reusableViews[identifier]!.contains(view) {
reusableViews[identifier]?.append(view)
} else {
reusableViews[identifier] = [view]
}
cleanupTimer?.invalidate()
cleanupTimer = Timer.scheduledTimer(timeInterval: lifeSpan, target: self,
selector: #selector(cleanup), userInfo: nil, repeats: false)
if let cleanupTimer = cleanupTimer {
cleanupTimer.fireDate = Date().addingTimeInterval(lifeSpan)
} else {
cleanupTimer = Timer.scheduledTimer(timeInterval: lifeSpan, target: self,
selector: #selector(cleanup), userInfo: nil, repeats: false)
}
}

public func dequeue<T: UIView> (_ defaultView: @autoclosure () -> T) -> T {
Expand All @@ -37,22 +55,25 @@ public class CollectionReuseViewManager: NSObject {
if let view = view as? CollectionViewReusableView {
view.prepareForReuse()
}
if !removeFromCollectionViewWhenReuse {
view.isHidden = false
}
view.reuseManager = self
return view
}

public func dequeue<T: UIView> (type: T.Type) -> T {
let identifier = NSStringFromClass(type.self)
let queuedView = reusableViews[identifier]?.popLast() as? T
let view = queuedView ?? type.init()
if let view = view as? CollectionViewReusableView {
view.prepareForReuse()
}
view.reuseManager = self
return view
return dequeue(type.init())
}

@objc func cleanup() {
for views in reusableViews.values {
for view in views {
view.removeFromSuperview()
}
}
reusableViews.removeAll()
cleanupTimer?.invalidate()
cleanupTimer = nil
}
}