Repository: teambition/TBEmptyDataSet
Branch: master
Commit: b1e704d33322
Files: 37
Total size: 109.0 KB
Directory structure:
gitextract_9vpatnox/
├── .gitignore
├── .swift-version
├── .swiftlint.yml
├── Example/
│ ├── .swiftlint.yml
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── icon-empty-events.imageset/
│ │ │ └── Contents.json
│ │ ├── icon-empty-message.imageset/
│ │ │ └── Contents.json
│ │ ├── icon-empty-photos.imageset/
│ │ │ └── Contents.json
│ │ └── loading.imageset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── Main.storyboard
│ ├── DemoViewController.swift
│ ├── EmptyDataDemoCollectionViewController.swift
│ ├── EmptyDataDemoTableViewController.swift
│ └── Info.plist
├── LICENSE.md
├── README.md
├── TBEmptyDataSet/
│ ├── Constants.swift
│ ├── EmptyDataView.swift
│ ├── Protocols.swift
│ ├── Supporting Files/
│ │ └── Info.plist
│ ├── TBEmptyDataSet.swift
│ └── WeakObjectContainer.swift
├── TBEmptyDataSet.podspec
├── TBEmptyDataSet.xcodeproj/
│ ├── project.pbxproj
│ ├── xcshareddata/
│ │ └── xcschemes/
│ │ └── TBEmptyDataSet.xcscheme
│ └── xcuserdata/
│ ├── hongxin.xcuserdatad/
│ │ └── xcschemes/
│ │ └── xcschememanagement.plist
│ └── zetasq.xcuserdatad/
│ └── xcschemes/
│ └── xcschememanagement.plist
├── TBEmptyDataSet.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
└── TBEmptyDataSetExample.xcodeproj/
├── project.pbxproj
├── project.xcworkspace/
│ └── contents.xcworkspacedata
└── xcuserdata/
├── hongxin.xcuserdatad/
│ └── xcschemes/
│ ├── TBEmptyDataSetExample.xcscheme
│ └── xcschememanagement.plist
└── zetasq.xcuserdatad/
└── xcschemes/
├── TBEmptyDataSetExample.xcscheme
└── xcschememanagement.plist
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
TBEmptyDataSet.xcworkspace/xcuserdata
================================================
FILE: .swift-version
================================================
5.0
================================================
FILE: .swiftlint.yml
================================================
disabled_rules: # rule identifiers to exclude from running
- line_length
- nesting
- variable_name_min_length
- cyclomatic_complexity
- class_delegate_protocol
- multiple_closures_with_trailing_closure
included: # paths to include during linting. `--path` is ignored if present. takes precendence over `excluded`.
excluded: # paths to ignore during linting. overridden by `included`.
- Carthage
# parameterized rules are first parameterized as a warning level, then error level.
line_length: 150
type_name:
min_length: 3 # only warning
max_length: # warning and error
warning: 100
error: 200
function_parameter_count: 10
function_body_length:
- 100
- 200
type_body_length:
- 300 # warning
- 400 # error
file_length:
- 1000 # warning
- 1500 # error
variable_name:
min_length: 2
max_length: 40
================================================
FILE: Example/.swiftlint.yml
================================================
disabled_rules: # rule identifiers to exclude from running
- line_length
- nesting
included: # paths to include during linting. `--path` is ignored if present. takes precendence over `excluded`.
excluded: # paths to ignore during linting. overridden by `included`.
- Carthage
# parameterized rules can be customized from this configuration file
line_length: 150
# parameterized rules are first parameterized as a warning level, then error level.
type_body_length:
- 300 # warning
- 400 # error
================================================
FILE: Example/AppDelegate.swift
================================================
//
// AppDelegate.swift
// TBEmptyDataSetExample
//
// Created by 洪鑫 on 15/11/19.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
return true
}
func applicationWillResignActive(_ application: UIApplication) {
}
func applicationDidEnterBackground(_ application: UIApplication) {
}
func applicationWillEnterForeground(_ application: UIApplication) {
}
func applicationDidBecomeActive(_ application: UIApplication) {
}
func applicationWillTerminate(_ application: UIApplication) {
}
}
================================================
FILE: Example/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/Assets.xcassets/icon-empty-events.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon-empty-events.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/Assets.xcassets/icon-empty-message.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon-empty-message.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/Assets.xcassets/icon-empty-photos.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon-empty-photos.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/Assets.xcassets/loading.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "loading@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "loading.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="kbE-4i-otZ">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13173"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Empty Data Demo Table View Controller-->
<scene sceneID="5qx-c9-kQh">
<objects>
<tableViewController id="Lch-ZU-4Kb" customClass="EmptyDataDemoTableViewController" customModule="TBEmptyDataSetExample" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="qN0-9C-fAP">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="dataSource" destination="Lch-ZU-4Kb" id="7Ht-DJ-jpu"/>
<outlet property="delegate" destination="Lch-ZU-4Kb" id="Ehn-JM-S7A"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="ScQ-bM-CdO"/>
<refreshControl key="refreshControl" opaque="NO" multipleTouchEnabled="YES" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="p9X-og-oGO">
<autoresizingMask key="autoresizingMask"/>
</refreshControl>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="LQ9-uv-mnW" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2372" y="220"/>
</scene>
<!--Empty Data Demo Collection View Controller-->
<scene sceneID="OLg-ZA-g8n">
<objects>
<collectionViewController id="FIk-rG-V0x" customClass="EmptyDataDemoCollectionViewController" customModule="TBEmptyDataSetExample" customModuleProvider="target" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="WoI-bx-7tf">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="AN4-8s-pSk">
<size key="itemSize" width="160" height="118"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="Cell" id="hIW-pB-eH7">
<rect key="frame" x="0.0" y="0.0" width="160" height="118"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="160" height="118"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Click to delete" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BEj-6c-73Q">
<rect key="frame" x="25.5" y="48" width="109.5" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.2196078431372549" green="0.2196078431372549" blue="0.2196078431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</view>
<color key="backgroundColor" red="0.86611149850000002" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="BEj-6c-73Q" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="hIW-pB-eH7" secondAttribute="leading" id="JOd-4d-wJP"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="BEj-6c-73Q" secondAttribute="trailing" id="dv6-Kt-w7I"/>
<constraint firstItem="BEj-6c-73Q" firstAttribute="centerY" secondItem="hIW-pB-eH7" secondAttribute="centerY" id="qrx-KL-dJl"/>
<constraint firstItem="BEj-6c-73Q" firstAttribute="centerX" secondItem="hIW-pB-eH7" secondAttribute="centerX" id="uh9-Xc-Hvo"/>
</constraints>
</collectionViewCell>
</cells>
<connections>
<outlet property="dataSource" destination="FIk-rG-V0x" id="Ie5-4i-wFd"/>
<outlet property="delegate" destination="FIk-rG-V0x" id="p57-cM-0vu"/>
</connections>
</collectionView>
</collectionViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="CUf-YB-2wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2372" y="969"/>
</scene>
<!--Demo View Controller-->
<scene sceneID="KuL-DV-c3x">
<objects>
<tableViewController id="0UU-b8-JN0" customClass="DemoViewController" customModule="TBEmptyDataSetExample" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="6n3-iw-5uM">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="dataSource" destination="0UU-b8-JN0" id="kMW-9Q-Sq7"/>
<outlet property="delegate" destination="0UU-b8-JN0" id="QxC-zl-gDt"/>
</connections>
</tableView>
<navigationItem key="navigationItem" id="XiQ-GK-l0D"/>
<connections>
<segue destination="Lch-ZU-4Kb" kind="show" identifier="ShowEmptyDataDemoTableView" id="roH-Lu-khf"/>
<segue destination="FIk-rG-V0x" kind="show" identifier="ShowEmptyDataDemoCollectionView" id="pHA-i3-d8D"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4v7-ty-bFt" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1533" y="562"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="Dg0-w9-0qB">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="kbE-4i-otZ" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="aL2-C2-A5C">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="0UU-b8-JN0" kind="relationship" relationship="rootViewController" id="FIc-3B-1LF"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="tDd-z5-ifx" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="721" y="562"/>
</scene>
</scenes>
</document>
================================================
FILE: Example/DemoViewController.swift
================================================
//
// DemoViewController.swift
// TBEmptyDataSetExample
//
// Created by 洪鑫 on 15/11/26.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
public struct EmptyData {
static let images = [#imageLiteral(resourceName: "icon-empty-photos"), #imageLiteral(resourceName: "icon-empty-events"), #imageLiteral(resourceName: "icon-empty-message")]
static let titles = ["无照片", "无日程", "无新消息"]
static let descriptions = ["你可以添加一些照片哦,让生活更精彩!", "暂时没有日程哦,添加一些日程吧!", "没有新消息哦,去找朋友聊聊天吧!"]
}
class DemoViewController: UITableViewController {
// MARK: - Structs
fileprivate struct Data {
static let examples = ["Empty Photos", "Empty Events", "Empty Message"]
static let sectionTitles = ["TableView", "CollectionView"]
}
fileprivate struct SegueIdentifier {
static let showTableView = "ShowEmptyDataDemoTableView"
static let showCollectionView = "ShowEmptyDataDemoCollectionView"
}
fileprivate struct CellIdentifier {
static let reuseIdentifier = "Cell"
}
// MARK: - Properties
var selectedIndexPath = IndexPath()
// MARK: - View life cycle
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "EmptyDataSet Example"
let backButton = UIBarButtonItem()
backButton.title = "Back"
navigationItem.backBarButtonItem = backButton
tableView.tableFooterView = UIView()
}
// MARK: - Table view data source and delegate
override func numberOfSections(in tableView: UITableView) -> Int {
return Data.sectionTitles.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Data.examples.count
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return Data.sectionTitles[section]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier.reuseIdentifier)
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: CellIdentifier.reuseIdentifier)
}
cell!.accessoryType = .disclosureIndicator
cell!.textLabel!.text = Data.examples[indexPath.row]
return cell!
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
selectedIndexPath = indexPath
if indexPath.section == 0 {
performSegue(withIdentifier: SegueIdentifier.showTableView, sender: self)
} else if indexPath.section == 1 {
performSegue(withIdentifier: SegueIdentifier.showCollectionView, sender: self)
}
tableView.deselectRow(at: indexPath, animated: true)
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == SegueIdentifier.showTableView {
if let emptyDataDemoTableViewController = segue.destination as? EmptyDataDemoTableViewController {
emptyDataDemoTableViewController.indexPath = selectedIndexPath
}
} else if segue.identifier == SegueIdentifier.showCollectionView {
if let emptyDataDemoCollectionViewController = segue.destination as? EmptyDataDemoCollectionViewController {
emptyDataDemoCollectionViewController.indexPath = selectedIndexPath
}
}
}
}
================================================
FILE: Example/EmptyDataDemoCollectionViewController.swift
================================================
//
// EmptyDataDemoCollectionViewController.swift
// TBEmptyDataSetExample
//
// Created by 洪鑫 on 15/11/24.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
import TBEmptyDataSet
class EmptyDataDemoCollectionViewController: UICollectionViewController {
// MARK: - Structs
fileprivate struct CellIdentifier {
static let reuseIdentifier = "Cell"
}
// MARK: - Properties
var indexPath = IndexPath()
fileprivate var isLoading = false
fileprivate var dataCount = 0
// MARK: - View life cycle
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "CollectionView"
collectionView?.backgroundColor = .white
collectionView?.emptyDataSetDataSource = self
collectionView?.emptyDataSetDelegate = self
if indexPath.row != 0 {
loadData(self)
}
}
// MARK: - Helper
func loadData(_ sender: Any) {
isLoading = true
let delayTime = DispatchTime.now() + Double(Int64(2 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime) { () -> Void in
self.dataCount = 4
self.isLoading = false
self.collectionView?.reloadData()
}
}
// MARK: - Collection view data source
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dataCount
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellIdentifier.reuseIdentifier, for: indexPath)
let maskLayer = CAShapeLayer()
let maskRect = cell.bounds
maskLayer.frame = maskRect
let cornerRadii = CGSize(width: 5, height: 5)
let maskPath = UIBezierPath(roundedRect: maskRect, byRoundingCorners: .allCorners, cornerRadii: cornerRadii)
maskLayer.path = maskPath.cgPath
cell.layer.mask = maskLayer
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.dataCount -= 1
collectionView.performBatchUpdates({
self.collectionView?.deleteItems(at: [indexPath])
}) { (_) in
}
}
}
extension EmptyDataDemoCollectionViewController: TBEmptyDataSetDataSource, TBEmptyDataSetDelegate {
// MARK: - TBEmptyDataSet data source
func imageForEmptyDataSet(in scrollView: UIScrollView) -> UIImage? {
return EmptyData.images[indexPath.row]
}
func titleForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
let title = EmptyData.titles[indexPath.row]
var attributes: [NSAttributedString.Key: Any]?
if indexPath.row == 1 {
attributes = [.font: UIFont.systemFont(ofSize: 22),
.foregroundColor: UIColor.gray]
} else if indexPath.row == 2 {
attributes = [.font: UIFont.systemFont(ofSize: 24),
.foregroundColor: UIColor.gray]
}
return NSAttributedString(string: title, attributes: attributes)
}
func descriptionForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
let description = EmptyData.descriptions[indexPath.row]
var attributes: [NSAttributedString.Key: Any]?
if indexPath.row == 1 {
attributes = [.font: UIFont.systemFont(ofSize: 17),
.foregroundColor: UIColor(red: 3 / 255, green: 169 / 255, blue: 244 / 255, alpha: 1)]
} else if indexPath.row == 2 {
attributes = [.font: UIFont.systemFont(ofSize: 18),
.foregroundColor: UIColor.purple]
}
return NSAttributedString(string: description, attributes: attributes)
}
func backgroundColorForEmptyDataSet(in scrollView: UIScrollView) -> UIColor? {
return UIColor(white: 0.95, alpha: 1)
}
func verticalOffsetForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
if let navigationBar = navigationController?.navigationBar {
return -navigationBar.frame.height * 0.75
}
return 0
}
func customViewForEmptyDataSet(in scrollView: UIScrollView) -> UIView? {
let loadingView: UIView = {
if indexPath.row == 2 {
return ExampleCustomView(frame: CGRect.zero)
}
let loadingImageView = UIImageView(image: #imageLiteral(resourceName: "loading"))
let view = UIView(frame: loadingImageView.frame)
view.addSubview(loadingImageView)
let animation: CABasicAnimation = {
let animation = CABasicAnimation(keyPath: "transform")
animation.fromValue = NSValue(caTransform3D: CATransform3DIdentity)
animation.toValue = NSValue(caTransform3D: CATransform3DMakeRotation(.pi / 2, 0, 0, 1))
animation.duration = 0.3
animation.isCumulative = true
animation.repeatCount = .greatestFiniteMagnitude
return animation
}()
loadingImageView.layer.add(animation, forKey: "loading")
return view
}()
if isLoading {
return loadingView
} else {
return nil
}
}
// MARK: - TBEmptyDataSet delegate
func emptyDataSetShouldDisplay(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetTapEnabled(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetScrollEnabled(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetDidTapEmptyView(in scrollView: UIScrollView) {
let alert = UIAlertController(title: nil, message: "Did Tap EmptyDataView!", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
func emptyDataSetWillAppear(in scrollView: UIScrollView) {
print("EmptyDataSet Will Appear!")
}
func emptyDataSetDidAppear(in scrollView: UIScrollView) {
print("EmptyDataSet Did Appear!")
}
func emptyDataSetWillDisappear(in scrollView: UIScrollView) {
print("EmptyDataSet Will Disappear!")
}
func emptyDataSetDidDisappear(in scrollView: UIScrollView) {
print("EmptyDataSet Did Disappear!")
}
}
extension EmptyDataDemoCollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 150, height: 90)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 20
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 20
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
collectionViewLayout.invalidateLayout()
coordinator.animate(alongsideTransition: { (_) -> Void in
}) { (_) -> Void in
}
}
}
class ExampleCustomView: UIView {
fileprivate lazy var contentLabel: UILabel = {
let contentLabel = UILabel()
contentLabel.numberOfLines = 0
contentLabel.textColor = .white
contentLabel.translatesAutoresizingMaskIntoConstraints = false
return contentLabel
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
fileprivate func commonInit() {
backgroundColor = .lightGray
layer.cornerRadius = 6
let activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge)
activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
activityIndicatorView.startAnimating()
contentLabel.text = "Loading... Please wait a moment...\n\n(This is a custom empty data view, which is using pure AutoLayout)"
addSubview(activityIndicatorView)
addSubview(contentLabel)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-15-[activityIndicatorView]-20-[contentLabel]-15-|", options: [], metrics: nil, views: ["activityIndicatorView": activityIndicatorView, "contentLabel": contentLabel]))
addConstraint(NSLayoutConstraint(item: activityIndicatorView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-15-[contentLabel]-15-|", options: [], metrics: nil, views: ["contentLabel": contentLabel]))
translatesAutoresizingMaskIntoConstraints = false
}
}
================================================
FILE: Example/EmptyDataDemoTableViewController.swift
================================================
//
// EmptyDataDemoTableViewController.swift
// TBEmptyDataSetExample
//
// Created by 洪鑫 on 15/11/24.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
import TBEmptyDataSet
class EmptyDataDemoTableViewController: UITableViewController {
// MARK: - Structs
fileprivate struct CellIdentifier {
static let reuseIdentifier = "Cell"
}
// MARK: - Properties
var indexPath = IndexPath()
fileprivate var isLoading = false
fileprivate var dataCount = 0
// MARK: - View life cycle
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "TableView"
tableView.tableFooterView = UIView()
refreshControl?.addTarget(self, action: #selector(fetchData(_:)), for: .valueChanged)
tableView.emptyDataSetDataSource = self
tableView.emptyDataSetDelegate = self
if indexPath.row != 0 {
loadData(self)
}
}
// MARK: - Helper
@objc func fetchData(_ sender: Any) {
let delayTime = DispatchTime.now() + Double(Int64(1.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime) { () -> Void in
self.dataCount = 7
self.tableView.reloadData()
self.refreshControl?.endRefreshing()
}
}
func loadData(_ sender: Any) {
isLoading = true
let delayTime = DispatchTime.now() + Double(Int64(1.75 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: delayTime) { () -> Void in
self.isLoading = false
self.tableView.reloadData()
}
}
// MARK: - Table view data source and delegate
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataCount
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier.reuseIdentifier)
if cell == nil {
cell = UITableViewCell(style: .value1, reuseIdentifier: CellIdentifier.reuseIdentifier)
}
cell!.textLabel?.text = "Cell"
cell!.detailTextLabel?.text = "Click to delete"
return cell!
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
tableView.beginUpdates()
dataCount -= 1
tableView.deleteRows(at: [indexPath], with: .fade)
tableView.endUpdates()
}
}
extension EmptyDataDemoTableViewController: TBEmptyDataSetDataSource, TBEmptyDataSetDelegate {
// MARK: - TBEmptyDataSet data source
func imageForEmptyDataSet(in scrollView: UIScrollView) -> UIImage? {
return EmptyData.images[indexPath.row]
}
func titleForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
let title = EmptyData.titles[indexPath.row]
var attributes: [NSAttributedString.Key: Any]?
if indexPath.row == 1 {
attributes = [.font: UIFont.systemFont(ofSize: 22),
.foregroundColor: UIColor.gray]
} else if indexPath.row == 2 {
attributes = [.font: UIFont.systemFont(ofSize: 24),
.foregroundColor: UIColor.gray]
}
return NSAttributedString(string: title, attributes: attributes)
}
func descriptionForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
let description = EmptyData.descriptions[indexPath.row]
var attributes: [NSAttributedString.Key: Any]?
if indexPath.row == 1 {
attributes = [.font: UIFont.systemFont(ofSize: 17),
.foregroundColor: UIColor(red: 3 / 255, green: 169 / 255, blue: 244 / 255, alpha: 1)]
} else if indexPath.row == 2 {
attributes = [.font: UIFont.systemFont(ofSize: 18),
.foregroundColor: UIColor.purple]
}
return NSAttributedString(string: description, attributes: attributes)
}
func verticalOffsetForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
if let navigationBar = navigationController?.navigationBar {
return -navigationBar.frame.height * 0.75
}
return 0
}
func verticalSpacesForEmptyDataSet(in scrollView: UIScrollView) -> [CGFloat] {
return [25, 8]
}
func customViewForEmptyDataSet(in scrollView: UIScrollView) -> UIView? {
if isLoading {
let activityIndicator = UIActivityIndicatorView(style: .gray)
activityIndicator.startAnimating()
return activityIndicator
}
return nil
}
// MARK: - TBEmptyDataSet delegate
func emptyDataSetShouldDisplay(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetTapEnabled(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetScrollEnabled(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetDidTapEmptyView(in scrollView: UIScrollView) {
let alert = UIAlertController(title: nil, message: "Did Tap EmptyDataView!", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
func emptyDataSetWillAppear(in scrollView: UIScrollView) {
print("EmptyDataSet Will Appear!")
}
func emptyDataSetDidAppear(in scrollView: UIScrollView) {
print("EmptyDataSet Did Appear!")
}
func emptyDataSetWillDisappear(in scrollView: UIScrollView) {
print("EmptyDataSet Will Disappear!")
}
func emptyDataSetDidDisappear(in scrollView: UIScrollView) {
print("EmptyDataSet Did Disappear!")
}
}
================================================
FILE: Example/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>3.0.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>23</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
Copyright (c) 2015 Teambition
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# TBEmptyDataSet
TBEmptyDataSet is an extension of UITableView/UICollectionView's super class, it will display a placeholder emptyDataSet when the data of tableView/collectionView is empty.
TBEmptyDataSet can be composed of an image, a title and a description, or you can set it as a custom view.

## How To Get Started
### Carthage
Specify "TBEmptyDataSet" in your ```Cartfile```:
```ogdl
github "teambition/TBEmptyDataSet"
```
### CocoaPods
Specify "TBEmptyDataSet" in your ```Podfile```:
```ruby
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!
pod 'TBEmptyDataSet'
```
### Usage
##### 1. Assign the data source and delegate
```swift
tableView.emptyDataSetDataSource = self
tableView.emptyDataSetDelegate = self
```
##### 2. Implement the data source and delegate
Data source functions:
```swift
func imageForEmptyDataSet(in scrollView: UIScrollView) -> UIImage? {
// return the image for EmptyDataSet
}
func titleForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
// return the title for EmptyDataSet
}
func descriptionForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
// return the description for EmptyDataSet
}
func imageTintColorForEmptyDataSet(in scrollView: UIScrollView) -> UIColor? {
// return the image tint color for EmptyDataSet
}
func backgroundColorForEmptyDataSet(in scrollView: UIScrollView) -> UIColor? {
// return the backgroundColor for EmptyDataSet
}
func verticalOffsetForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
// return the vertical offset for EmptyDataSet, default is 0
}
func verticalSpacesForEmptyDataSet(in scrollView: UIScrollView) -> [CGFloat] {
// return the vertical spaces from top to bottom for EmptyDataSet, default is [12, 12]
}
func titleMarginForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
// return the minimum horizontal margin space for title, default is 15
}
func descriptionMarginForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
// return the minimum horizontal margin space for description, default is 15
}
func customViewForEmptyDataSet(in scrollView: UIScrollView) -> UIView? {
// return an UIView instance for EmptyDataSet
}
```
Delegate functions:
```swift
func emptyDataSetShouldDisplay(in scrollView: UIScrollView) -> Bool {
// should display EmptyDataSet or not, default is true
}
func emptyDataSetTapEnabled(in scrollView: UIScrollView) -> Bool {
// enable tap gesture or not, default is true
}
func emptyDataSetScrollEnabled(in scrollView: UIScrollView) -> Bool {
// scrollView can scroll or not, default is false
}
func emptyDataSetDidTapEmptyView(in scrollView: UIScrollView) {
// do something
}
func emptyDataSetWillAppear(in scrollView: UIScrollView) {
// do something
}
func emptyDataSetDidAppear(in scrollView: UIScrollView) {
// do something
}
func emptyDataSetWillDisappear(in scrollView: UIScrollView) {
// do something
}
func emptyDataSetDidDisappear(in scrollView: UIScrollView) {
// do something
}
```
##### 3. Data source events (inserting, deleting, reloading, etc.)
TBEmptyDataSet will update automatically when the data source of table view or collection view changes.
To be specific:
* For UITableView, it updates when ```endUpdates()``` is called.
* For both UITableView and UICollectionView, it updates when ```performBatchUpdates(_:completion:)``` is completed.
* For both UITableView and UICollectionView, it updates when ```reloadData()``` is called.
## Minimum Requirement
iOS 8.0
## Release Notes
* [Release Notes](https://github.com/teambition/TBEmptyDataSet/releases)
## License
TBEmptyDataSet is released under the MIT license. See [LICENSE](https://github.com/teambition/TBEmptyDataSet/blob/master/LICENSE.md) for details.
## More Info
Have a question? Please [open an issue](https://github.com/teambition/TBEmptyDataSet/issues/new)!
================================================
FILE: TBEmptyDataSet/Constants.swift
================================================
//
// Constants.swift
// TBEmptyDataSet
//
// Created by Xin Hong on 15/11/19.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
// swiftlint:disable variable_name
internal struct AssociatedKeys {
static var emptyDataSetDataSource = "emptyDataSetDataSource"
static var emptyDataSetDelegate = "emptyDataSetDelegate"
static var emptyDataView = "emptyDataView"
}
internal struct Selectors {
static let tableViewSwizzledReloadData = #selector(UIScrollView.tb_tableViewSwizzledReloadData)
static let tableViewSwizzledEndUpdates = #selector(UIScrollView.tb_tableViewSwizzledEndUpdates)
@available(iOS 11.0, *)
static let tableViewSwizzledPerformBatchUpdates = #selector(UIScrollView.tb_tableViewSwizzledPerformBatchUpdates(_:completion:))
static let collectionViewSwizzledReloadData = #selector(UIScrollView.tb_collectionViewSwizzledReloadData)
static let collectionViewSwizzledPerformBatchUpdates = #selector(UIScrollView.tb_collectionViewSwizzledPerformBatchUpdates(_:completion:))
}
internal struct TableViewSelectors {
static let reloadData = #selector(UITableView.reloadData)
static let endUpdates = #selector(UITableView.endUpdates)
static let numberOfSections = #selector(UITableViewDataSource.numberOfSections(in:))
@available(iOS 11.0, *)
static let performBatchUpdates = #selector(UITableView.performBatchUpdates(_:completion:))
}
internal struct CollectionViewSelectors {
static let reloadData = #selector(UICollectionView.reloadData)
static let numberOfSections = #selector(UICollectionViewDataSource.numberOfSections(in:))
static let performBatchUpdates = #selector(UICollectionView.performBatchUpdates(_:completion:))
}
internal struct DefaultValues {
static let verticalOffset: CGFloat = 0
static let verticalSpace: CGFloat = 12
static let verticalSpaces = [verticalSpace, verticalSpace]
static let titleMargin: CGFloat = 15
static let descriptionMargin: CGFloat = 15
}
================================================
FILE: TBEmptyDataSet/EmptyDataView.swift
================================================
//
// EmptyDataView.swift
// TBEmptyDataSet
//
// Created by Xin Hong on 15/11/19.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
internal class EmptyDataView: UIView {
fileprivate struct ViewStrings {
static let contentView = "contentView"
static let imageView = "imageView"
static let titleLabel = "titleLabel"
static let descriptionLabel = "descriptionLabel"
static let customView = "customView"
}
// MARK: - Properties
internal lazy var contentView: UIView = {
let contentView = UIView()
contentView.translatesAutoresizingMaskIntoConstraints = false
contentView.backgroundColor = .clear
contentView.alpha = 0
return contentView
}()
internal lazy var imageView: UIImageView = { [unowned self] in
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.backgroundColor = .clear
imageView.contentMode = .scaleAspectFill
self.contentView.addSubview(imageView)
return imageView
}()
internal lazy var titleLabel: UILabel = { [unowned self] in
let titleLabel = UILabel()
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.backgroundColor = .clear
titleLabel.font = .systemFont(ofSize: 27)
titleLabel.textColor = UIColor(white: 0.6, alpha: 1)
titleLabel.textAlignment = .center
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
self.contentView.addSubview(titleLabel)
return titleLabel
}()
internal lazy var descriptionLabel: UILabel = { [unowned self] in
let descriptionLabel = UILabel()
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
descriptionLabel.backgroundColor = .clear
descriptionLabel.font = .systemFont(ofSize: 17)
descriptionLabel.textColor = UIColor(white: 0.6, alpha: 1)
descriptionLabel.textAlignment = .center
descriptionLabel.lineBreakMode = .byWordWrapping
descriptionLabel.numberOfLines = 0
self.contentView.addSubview(descriptionLabel)
return descriptionLabel
}()
internal var customView: UIView? {
willSet {
if let customView = customView {
customView.removeFromSuperview()
}
}
didSet {
if let customView = customView {
contentView.addSubview(customView)
}
}
}
internal var tapGesture: UITapGestureRecognizer?
internal var verticalOffset = DefaultValues.verticalOffset
internal var verticalSpaces = DefaultValues.verticalSpaces
internal var titleMargin = DefaultValues.titleMargin
internal var descriptionMargin = DefaultValues.descriptionMargin
// MARK: - Helper
fileprivate func shouldShowImageView() -> Bool {
return imageView.image != nil
}
fileprivate func shouldShowTitleLabel() -> Bool {
if let title = titleLabel.attributedText {
return title.length > 0
}
return false
}
fileprivate func shouldShowDescriptionLabel() -> Bool {
if let description = descriptionLabel.attributedText {
return description.length > 0
}
return false
}
fileprivate func removeAllConstraints() {
contentView.removeConstraints(contentView.constraints)
removeConstraints(constraints)
}
// MARK: - View life cycle
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(self.contentView)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func didMoveToSuperview() {
frame = super.bounds
UIView.animate(withDuration: 0.25, animations: { () -> Void in
self.contentView.alpha = 1
})
}
// MARK: - Actions
internal func setConstraints() {
let centerX = NSLayoutConstraint(item: contentView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)
let centerY = NSLayoutConstraint(item: contentView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: verticalOffset)
addConstraint(centerX)
addConstraint(centerY)
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[\(ViewStrings.contentView)]|", options: [], metrics: nil, views: [ViewStrings.contentView: contentView]))
if let customView = customView {
let translatesFrameIntoConstraints = customView.translatesAutoresizingMaskIntoConstraints
customView.translatesAutoresizingMaskIntoConstraints = false
if translatesFrameIntoConstraints {
contentView.addConstraint(NSLayoutConstraint(item: customView, attribute: .width, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: customView.frame.width))
contentView.addConstraint(NSLayoutConstraint(item: customView, attribute: .height, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: customView.frame.height))
contentView.addConstraint(NSLayoutConstraint(item: customView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1, constant: 0))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[\(ViewStrings.customView)]|", options: [], metrics: nil, views: [ViewStrings.customView: customView]))
} else {
contentView.addConstraint(NSLayoutConstraint(item: customView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1, constant: 0))
contentView.addConstraint(NSLayoutConstraint(item: customView, attribute: .leading, relatedBy: .greaterThanOrEqual, toItem: contentView, attribute: .leading, multiplier: 1, constant: 0))
contentView.addConstraint(NSLayoutConstraint(item: customView, attribute: .trailing, relatedBy: .lessThanOrEqual, toItem: contentView, attribute: .trailing, multiplier: 1, constant: 0))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[\(ViewStrings.customView)]|", options: [], metrics: nil, views: [ViewStrings.customView: customView]))
}
} else {
var viewStrings = [String]()
var views = [String: UIView]()
if shouldShowImageView() {
if imageView.superview == nil {
contentView.addSubview(imageView)
}
let viewString = ViewStrings.imageView
viewStrings.append(viewString)
views[viewString] = imageView
contentView.addConstraint(NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1, constant: 0))
} else {
imageView.removeFromSuperview()
}
if shouldShowTitleLabel() {
if titleLabel.superview == nil {
contentView.addSubview(titleLabel)
}
let viewString = ViewStrings.titleLabel
viewStrings.append(viewString)
views[viewString] = titleLabel
contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1, constant: 0))
contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .leading, relatedBy: .greaterThanOrEqual, toItem: contentView, attribute: .leading, multiplier: 1, constant: titleMargin))
contentView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .trailing, relatedBy: .greaterThanOrEqual, toItem: titleLabel, attribute: .trailing, multiplier: 1, constant: titleMargin))
} else {
titleLabel.removeFromSuperview()
}
if shouldShowDescriptionLabel() {
if descriptionLabel.superview == nil {
contentView.addSubview(descriptionLabel)
}
let viewString = ViewStrings.descriptionLabel
viewStrings.append(viewString)
views[viewString] = descriptionLabel
contentView.addConstraint(NSLayoutConstraint(item: descriptionLabel, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1, constant: 0))
contentView.addConstraint(NSLayoutConstraint(item: descriptionLabel, attribute: .leading, relatedBy: .greaterThanOrEqual, toItem: contentView, attribute: .leading, multiplier: 1, constant: descriptionMargin))
contentView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .trailing, relatedBy: .greaterThanOrEqual, toItem: descriptionLabel, attribute: .trailing, multiplier: 1, constant: descriptionMargin))
} else {
descriptionLabel.removeFromSuperview()
}
var verticalFormat = String()
for (index, viewString) in viewStrings.enumerated() {
verticalFormat += "[\(viewString)]"
if index != viewStrings.count - 1 {
let verticalSpace = index < verticalSpaces.count ? verticalSpaces[index] : DefaultValues.verticalSpace
verticalFormat += "-(\(verticalSpace))-"
}
}
if !verticalFormat.isEmpty {
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|\(verticalFormat)|", options: [], metrics: nil, views: views))
}
}
}
internal func prepareForDisplay() {
imageView.image = nil
titleLabel.attributedText = nil
descriptionLabel.attributedText = nil
customView = nil
removeAllConstraints()
}
internal func reset() {
imageView.image = nil
titleLabel.attributedText = nil
descriptionLabel.attributedText = nil
customView = nil
tapGesture = nil
removeAllConstraints()
}
}
================================================
FILE: TBEmptyDataSet/Protocols.swift
================================================
//
// Protocols.swift
// TBEmptyDataSet
//
// Created by Xin Hong on 15/11/19.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
public protocol TBEmptyDataSetDataSource {
func imageForEmptyDataSet(in scrollView: UIScrollView) -> UIImage?
func titleForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString?
func descriptionForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString?
func imageTintColorForEmptyDataSet(in scrollView: UIScrollView) -> UIColor?
func backgroundColorForEmptyDataSet(in scrollView: UIScrollView) -> UIColor?
func verticalOffsetForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat
func verticalSpacesForEmptyDataSet(in scrollView: UIScrollView) -> [CGFloat]
func titleMarginForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat
func descriptionMarginForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat
func customViewForEmptyDataSet(in scrollView: UIScrollView) -> UIView?
}
public protocol TBEmptyDataSetDelegate {
func emptyDataSetShouldDisplay(in scrollView: UIScrollView) -> Bool
func emptyDataSetTapEnabled(in scrollView: UIScrollView) -> Bool
func emptyDataSetScrollEnabled(in scrollView: UIScrollView) -> Bool
func emptyDataSetDidTapEmptyView(in scrollView: UIScrollView)
func emptyDataSetWillAppear(in scrollView: UIScrollView)
func emptyDataSetDidAppear(in scrollView: UIScrollView)
func emptyDataSetWillDisappear(in scrollView: UIScrollView)
func emptyDataSetDidDisappear(in scrollView: UIScrollView)
}
public extension TBEmptyDataSetDataSource {
func imageForEmptyDataSet(in scrollView: UIScrollView) -> UIImage? {
return nil
}
func titleForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
return nil
}
func descriptionForEmptyDataSet(in scrollView: UIScrollView) -> NSAttributedString? {
return nil
}
func imageTintColorForEmptyDataSet(in scrollView: UIScrollView) -> UIColor? {
return nil
}
func backgroundColorForEmptyDataSet(in scrollView: UIScrollView) -> UIColor? {
return nil
}
func verticalOffsetForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
return DefaultValues.verticalOffset
}
func verticalSpacesForEmptyDataSet(in scrollView: UIScrollView) -> [CGFloat] {
return DefaultValues.verticalSpaces
}
func titleMarginForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
return DefaultValues.titleMargin
}
func descriptionMarginForEmptyDataSet(in scrollView: UIScrollView) -> CGFloat {
return DefaultValues.descriptionMargin
}
func customViewForEmptyDataSet(in scrollView: UIScrollView) -> UIView? {
return nil
}
}
public extension TBEmptyDataSetDelegate {
func emptyDataSetShouldDisplay(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetTapEnabled(in scrollView: UIScrollView) -> Bool {
return true
}
func emptyDataSetScrollEnabled(in scrollView: UIScrollView) -> Bool {
return false
}
func emptyDataSetDidTapEmptyView(in scrollView: UIScrollView) {
}
func emptyDataSetWillAppear(in scrollView: UIScrollView) {
}
func emptyDataSetDidAppear(in scrollView: UIScrollView) {
}
func emptyDataSetWillDisappear(in scrollView: UIScrollView) {
}
func emptyDataSetDidDisappear(in scrollView: UIScrollView) {
}
}
================================================
FILE: TBEmptyDataSet/Supporting Files/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>3.0.2</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
================================================
FILE: TBEmptyDataSet/TBEmptyDataSet.swift
================================================
//
// TBEmptyDataSet.swift
// TBEmptyDataSet
//
// Created by Xin Hong on 15/11/19.
// Copyright © 2015年 Teambition. All rights reserved.
//
import UIKit
extension UIScrollView {
// MARK: - Properties
public var emptyDataSetDataSource: TBEmptyDataSetDataSource? {
get {
let container = objc_getAssociatedObject(self, &AssociatedKeys.emptyDataSetDataSource) as? WeakObjectContainer
return container?.object as? TBEmptyDataSetDataSource
}
set {
if let newValue = newValue {
objc_setAssociatedObject(self, &AssociatedKeys.emptyDataSetDataSource, WeakObjectContainer(object: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
switch self {
case is UITableView:
UITableView.tb_swizzleTableViewReloadData
UITableView.tb_swizzleTableViewEndUpdates
if #available(iOS 11.0, *) {
UITableView.tb_swizzleTableViewPerformBatchUpdates
}
case is UICollectionView:
UICollectionView.tb_swizzleCollectionViewReloadData
UICollectionView.tb_swizzleCollectionViewPerformBatchUpdates
default:
break
}
} else {
handlingInvalidEmptyDataSet()
}
}
}
public var emptyDataSetDelegate: TBEmptyDataSetDelegate? {
get {
let container = objc_getAssociatedObject(self, &AssociatedKeys.emptyDataSetDelegate) as? WeakObjectContainer
return container?.object as? TBEmptyDataSetDelegate
}
set {
if let newValue = newValue {
objc_setAssociatedObject(self, &AssociatedKeys.emptyDataSetDelegate, WeakObjectContainer(object: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
} else {
handlingInvalidEmptyDataSet()
}
}
}
internal var emptyDataView: EmptyDataView? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.emptyDataView) as? EmptyDataView
}
set {
objc_setAssociatedObject(self, &AssociatedKeys.emptyDataView, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
// MARK: - Public
public var emptyDataViewVisible: Bool {
if let emptyDataView = emptyDataView {
return !emptyDataView.isHidden
}
return false
}
public func updateEmptyDataSetIfNeeded() {
reloadEmptyDataSet()
}
// MARK: - Data source and delegate getters
fileprivate func emptyDataSetImage() -> UIImage? {
return emptyDataSetDataSource?.imageForEmptyDataSet(in: self)
}
fileprivate func emptyDataSetTitle() -> NSAttributedString? {
return emptyDataSetDataSource?.titleForEmptyDataSet(in: self)
}
fileprivate func emptyDataSetDescription() -> NSAttributedString? {
return emptyDataSetDataSource?.descriptionForEmptyDataSet(in: self)
}
fileprivate func emptyDataSetImageTintColor() -> UIColor? {
return emptyDataSetDataSource?.imageTintColorForEmptyDataSet(in: self)
}
fileprivate func emptyDataSetBackgroundColor() -> UIColor? {
return emptyDataSetDataSource?.backgroundColorForEmptyDataSet(in: self)
}
fileprivate func emptyDataSetVerticalOffset() -> CGFloat {
return emptyDataSetDataSource?.verticalOffsetForEmptyDataSet(in: self) ?? DefaultValues.verticalOffset
}
fileprivate func emptyDataSetVerticalSpaces() -> [CGFloat] {
return emptyDataSetDataSource?.verticalSpacesForEmptyDataSet(in: self) ?? DefaultValues.verticalSpaces
}
fileprivate func emptyDataSetTitleMargin() -> CGFloat {
return emptyDataSetDataSource?.titleMarginForEmptyDataSet(in: self) ?? DefaultValues.titleMargin
}
fileprivate func emptyDataSetDescriptionMargin() -> CGFloat {
return emptyDataSetDataSource?.descriptionMarginForEmptyDataSet(in: self) ?? DefaultValues.descriptionMargin
}
fileprivate func emptyDataSetCustomView() -> UIView? {
return emptyDataSetDataSource?.customViewForEmptyDataSet(in: self)
}
fileprivate func emptyDataSetShouldDisplay() -> Bool {
return emptyDataSetDelegate?.emptyDataSetShouldDisplay(in: self) ?? true
}
fileprivate func emptyDataSetTapEnabled() -> Bool {
return emptyDataSetDelegate?.emptyDataSetTapEnabled(in: self) ?? true
}
fileprivate func emptyDataSetScrollEnabled() -> Bool {
return emptyDataSetDelegate?.emptyDataSetScrollEnabled(in: self) ?? false
}
// MARK: - Helper
@objc func didTapEmptyDataView(_ sender: Any) {
emptyDataSetDelegate?.emptyDataSetDidTapEmptyView(in: self)
}
fileprivate func makeEmptyDataView() -> EmptyDataView {
let emptyDataView = EmptyDataView(frame: frame)
emptyDataView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
emptyDataView.isHidden = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapEmptyDataView(_:)))
emptyDataView.addGestureRecognizer(tapGesture)
emptyDataView.tapGesture = tapGesture
return emptyDataView
}
fileprivate func emptyDataSetAvailable() -> Bool {
if emptyDataSetDataSource != nil {
return (self is UITableView) || (self is UICollectionView)
}
return false
}
fileprivate func cellsCount() -> Int {
var count = 0
if let tableView = self as? UITableView {
if let dataSource = tableView.dataSource {
if dataSource.responds(to: TableViewSelectors.numberOfSections) {
let sections = dataSource.numberOfSections?(in: tableView) ?? 0
for section in 0..<sections {
count += dataSource.tableView(tableView, numberOfRowsInSection: section)
}
}
}
} else if let collectionView = self as? UICollectionView {
if let dataSource = collectionView.dataSource {
if dataSource.responds(to: CollectionViewSelectors.numberOfSections) {
let sections = dataSource.numberOfSections?(in: collectionView) ?? 0
for section in 0..<sections {
count += dataSource.collectionView(collectionView, numberOfItemsInSection: section)
}
}
}
}
return count
}
fileprivate func handlingInvalidEmptyDataSet() {
emptyDataSetDelegate?.emptyDataSetWillDisappear(in: self)
emptyDataView?.reset()
emptyDataView?.removeFromSuperview()
emptyDataView = nil
isScrollEnabled = true
emptyDataSetDelegate?.emptyDataSetDidDisappear(in: self)
}
// MARK: - Display
fileprivate func reloadEmptyDataSet() {
guard emptyDataSetAvailable() else {
return
}
guard emptyDataSetShouldDisplay() && cellsCount() == 0 else {
if emptyDataViewVisible {
handlingInvalidEmptyDataSet()
}
return
}
let emptyDataView: EmptyDataView = {
if let emptyDataView = self.emptyDataView {
return emptyDataView
} else {
let emptyDataView = makeEmptyDataView()
self.emptyDataView = emptyDataView
return emptyDataView
}
}()
emptyDataSetDelegate?.emptyDataSetWillAppear(in: self)
if emptyDataView.superview == nil {
if (self is UITableView || self is UICollectionView) && subviews.count > 1 {
insertSubview(emptyDataView, at: 0)
} else {
addSubview(emptyDataView)
}
}
emptyDataView.prepareForDisplay()
emptyDataView.verticalOffset = emptyDataSetVerticalOffset()
emptyDataView.verticalSpaces = emptyDataSetVerticalSpaces()
emptyDataView.titleMargin = emptyDataSetTitleMargin()
emptyDataView.descriptionMargin = emptyDataSetDescriptionMargin()
if let customView = emptyDataSetCustomView() {
emptyDataView.customView = customView
} else {
if let imageTintColor = emptyDataSetImageTintColor() {
emptyDataView.imageView.image = emptyDataSetImage()?.withRenderingMode(.alwaysTemplate)
emptyDataView.imageView.tintColor = imageTintColor
} else {
emptyDataView.imageView.image = emptyDataSetImage()?.withRenderingMode(.alwaysOriginal)
}
emptyDataView.titleLabel.attributedText = emptyDataSetTitle()
emptyDataView.descriptionLabel.attributedText = emptyDataSetDescription()
}
emptyDataView.backgroundColor = emptyDataSetBackgroundColor()
emptyDataView.isHidden = false
emptyDataView.clipsToBounds = true
emptyDataView.tapGesture?.isEnabled = emptyDataSetTapEnabled()
isScrollEnabled = emptyDataSetScrollEnabled()
emptyDataView.setConstraints()
emptyDataView.layoutIfNeeded()
emptyDataSetDelegate?.emptyDataSetDidAppear(in: self)
}
// MARK: - Method swizzling
fileprivate class func tb_swizzleMethod(for aClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
guard let originalMethod = class_getInstanceMethod(aClass, originalSelector), let swizzledMethod = class_getInstanceMethod(aClass, swizzledSelector) else {
return
}
let didAddMethod = class_addMethod(aClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(aClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
// swiftlint:disable variable_name
fileprivate static let tb_swizzleTableViewReloadData: () = {
let originalSelector = TableViewSelectors.reloadData
let swizzledSelector = Selectors.tableViewSwizzledReloadData
tb_swizzleMethod(for: UITableView.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()
// swiftlint:disable variable_name
fileprivate static let tb_swizzleTableViewEndUpdates: () = {
let originalSelector = TableViewSelectors.endUpdates
let swizzledSelector = Selectors.tableViewSwizzledEndUpdates
tb_swizzleMethod(for: UITableView.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()
// swiftlint:disable variable_name
@available(iOS 11.0, *)
fileprivate static let tb_swizzleTableViewPerformBatchUpdates: () = {
let originalSelector = TableViewSelectors.performBatchUpdates
let swizzledSelector = Selectors.tableViewSwizzledPerformBatchUpdates
tb_swizzleMethod(for: UITableView.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()
// swiftlint:disable variable_name
fileprivate static let tb_swizzleCollectionViewReloadData: () = {
let originalSelector = CollectionViewSelectors.reloadData
let swizzledSelector = Selectors.collectionViewSwizzledReloadData
tb_swizzleMethod(for: UICollectionView.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()
// swiftlint:disable variable_name
fileprivate static let tb_swizzleCollectionViewPerformBatchUpdates: () = {
let originalSelector = CollectionViewSelectors.performBatchUpdates
let swizzledSelector = Selectors.collectionViewSwizzledPerformBatchUpdates
tb_swizzleMethod(for: UICollectionView.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}()
@objc
func tb_tableViewSwizzledReloadData() {
tb_tableViewSwizzledReloadData()
reloadEmptyDataSet()
}
@objc
func tb_tableViewSwizzledEndUpdates() {
tb_tableViewSwizzledEndUpdates()
reloadEmptyDataSet()
}
@available(iOS 11.0, *)
@objc
func tb_tableViewSwizzledPerformBatchUpdates(_ updates: (() -> Void)?, completion: ((Bool) -> Void)?) {
tb_tableViewSwizzledPerformBatchUpdates(updates) { [weak self](completed) in
completion?(completed)
self?.reloadEmptyDataSet()
}
}
@objc
func tb_collectionViewSwizzledReloadData() {
tb_collectionViewSwizzledReloadData()
reloadEmptyDataSet()
}
@objc
func tb_collectionViewSwizzledPerformBatchUpdates(_ updates: (() -> Void)?, completion: ((Bool) -> Void)?) {
tb_collectionViewSwizzledPerformBatchUpdates(updates) { [weak self](completed) in
completion?(completed)
self?.reloadEmptyDataSet()
}
}
}
================================================
FILE: TBEmptyDataSet/WeakObjectContainer.swift
================================================
//
// WeakObjectContainer.swift
// TBEmptyDataSet
//
// Created by Xin Hong on 2016/11/4.
// Copyright © 2016年 Teambition. All rights reserved.
//
import UIKit
class WeakObjectContainer: NSObject {
weak var object: AnyObject?
init(object: Any) {
super.init()
self.object = object as AnyObject
}
}
================================================
FILE: TBEmptyDataSet.podspec
================================================
Pod::Spec.new do |s|
s.name = "TBEmptyDataSet"
s.version = "3.0.2"
s.summary = "An extension of UITableView/UICollectionView's super class, it will display a placeholder when the data is empty."
s.homepage = "https://github.com/teambition/TBEmptyDataSet"
s.license = { :type => "MIT", :file => "LICENSE.md" }
s.author = "Xin Hong"
s.source = { :git => "https://github.com/teambition/TBEmptyDataSet.git", :tag => s.version.to_s }
s.source_files = "TBEmptyDataSet/*.swift"
s.platform = :ios, "8.0"
s.requires_arc = true
s.frameworks = "Foundation", "UIKit"
end
================================================
FILE: TBEmptyDataSet.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
D331287B1DCC259C00773E72 /* WeakObjectContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D331287A1DCC259C00773E72 /* WeakObjectContainer.swift */; };
D33C7C741C44DCA000E1687A /* TBEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33C7C731C44DCA000E1687A /* TBEmptyDataSet.swift */; };
D33C7C781C44DF0A00E1687A /* EmptyDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33C7C771C44DF0A00E1687A /* EmptyDataView.swift */; };
D33C7C7A1C44E17000E1687A /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33C7C791C44E17000E1687A /* Constants.swift */; };
D33C7C7C1C44E21700E1687A /* Protocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = D33C7C7B1C44E21700E1687A /* Protocols.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
D331287A1DCC259C00773E72 /* WeakObjectContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakObjectContainer.swift; sourceTree = "<group>"; };
D33C7C671C44DBED00E1687A /* TBEmptyDataSet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TBEmptyDataSet.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D33C7C731C44DCA000E1687A /* TBEmptyDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TBEmptyDataSet.swift; sourceTree = "<group>"; };
D33C7C751C44DCC200E1687A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D33C7C771C44DF0A00E1687A /* EmptyDataView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyDataView.swift; sourceTree = "<group>"; };
D33C7C791C44E17000E1687A /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
D33C7C7B1C44E21700E1687A /* Protocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Protocols.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D33C7C631C44DBED00E1687A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D33C7C5D1C44DBED00E1687A = {
isa = PBXGroup;
children = (
D33C7C691C44DBED00E1687A /* TBEmptyDataSet */,
D33C7C721C44DC8B00E1687A /* Supporting Files */,
D33C7C681C44DBED00E1687A /* Products */,
);
sourceTree = "<group>";
};
D33C7C681C44DBED00E1687A /* Products */ = {
isa = PBXGroup;
children = (
D33C7C671C44DBED00E1687A /* TBEmptyDataSet.framework */,
);
name = Products;
sourceTree = "<group>";
};
D33C7C691C44DBED00E1687A /* TBEmptyDataSet */ = {
isa = PBXGroup;
children = (
D33C7C791C44E17000E1687A /* Constants.swift */,
D33C7C7B1C44E21700E1687A /* Protocols.swift */,
D33C7C771C44DF0A00E1687A /* EmptyDataView.swift */,
D33C7C731C44DCA000E1687A /* TBEmptyDataSet.swift */,
D331287A1DCC259C00773E72 /* WeakObjectContainer.swift */,
);
path = TBEmptyDataSet;
sourceTree = "<group>";
};
D33C7C721C44DC8B00E1687A /* Supporting Files */ = {
isa = PBXGroup;
children = (
D33C7C751C44DCC200E1687A /* Info.plist */,
);
name = "Supporting Files";
path = "TBEmptyDataSet/Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D33C7C641C44DBED00E1687A /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
D33C7C661C44DBED00E1687A /* TBEmptyDataSet */ = {
isa = PBXNativeTarget;
buildConfigurationList = D33C7C6F1C44DBED00E1687A /* Build configuration list for PBXNativeTarget "TBEmptyDataSet" */;
buildPhases = (
D33C7C621C44DBED00E1687A /* Sources */,
D33C7C631C44DBED00E1687A /* Frameworks */,
D33C7C641C44DBED00E1687A /* Headers */,
D33C7C651C44DBED00E1687A /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = TBEmptyDataSet;
productName = TBEmptyDataSet;
productReference = D33C7C671C44DBED00E1687A /* TBEmptyDataSet.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D33C7C5E1C44DBED00E1687A /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = Teambition;
TargetAttributes = {
D33C7C661C44DBED00E1687A = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 1020;
};
};
};
buildConfigurationList = D33C7C611C44DBED00E1687A /* Build configuration list for PBXProject "TBEmptyDataSet" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = D33C7C5D1C44DBED00E1687A;
productRefGroup = D33C7C681C44DBED00E1687A /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D33C7C661C44DBED00E1687A /* TBEmptyDataSet */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D33C7C651C44DBED00E1687A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D33C7C621C44DBED00E1687A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D33C7C781C44DF0A00E1687A /* EmptyDataView.swift in Sources */,
D331287B1DCC259C00773E72 /* WeakObjectContainer.swift in Sources */,
D33C7C7C1C44E21700E1687A /* Protocols.swift in Sources */,
D33C7C741C44DCA000E1687A /* TBEmptyDataSet.swift in Sources */,
D33C7C7A1C44E17000E1687A /* Constants.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
D33C7C6D1C44DBED00E1687A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
D33C7C6E1C44DBED00E1687A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
D33C7C701C44DBED00E1687A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "$(SRCROOT)/TBEmptyDataSet/Supporting Files/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = Teambition.TBEmptyDataSet;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
D33C7C711C44DBED00E1687A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = "$(SRCROOT)/TBEmptyDataSet/Supporting Files/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = Teambition.TBEmptyDataSet;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D33C7C611C44DBED00E1687A /* Build configuration list for PBXProject "TBEmptyDataSet" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D33C7C6D1C44DBED00E1687A /* Debug */,
D33C7C6E1C44DBED00E1687A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D33C7C6F1C44DBED00E1687A /* Build configuration list for PBXNativeTarget "TBEmptyDataSet" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D33C7C701C44DBED00E1687A /* Debug */,
D33C7C711C44DBED00E1687A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D33C7C5E1C44DBED00E1687A /* Project object */;
}
================================================
FILE: TBEmptyDataSet.xcodeproj/xcshareddata/xcschemes/TBEmptyDataSet.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D33C7C661C44DBED00E1687A"
BuildableName = "TBEmptyDataSet.framework"
BlueprintName = "TBEmptyDataSet"
ReferencedContainer = "container:TBEmptyDataSet.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D33C7C661C44DBED00E1687A"
BuildableName = "TBEmptyDataSet.framework"
BlueprintName = "TBEmptyDataSet"
ReferencedContainer = "container:TBEmptyDataSet.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D33C7C661C44DBED00E1687A"
BuildableName = "TBEmptyDataSet.framework"
BlueprintName = "TBEmptyDataSet"
ReferencedContainer = "container:TBEmptyDataSet.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: TBEmptyDataSet.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>TBEmptyDataSet.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>D33C7C661C44DBED00E1687A</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
================================================
FILE: TBEmptyDataSet.xcodeproj/xcuserdata/zetasq.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>TBEmptyDataSet.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>D33C7C661C44DBED00E1687A</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
================================================
FILE: TBEmptyDataSet.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:TBEmptyDataSet.xcodeproj">
</FileRef>
<FileRef
location = "group:TBEmptyDataSetExample.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: TBEmptyDataSet.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
================================================
FILE: TBEmptyDataSetExample.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
D3013DFB1C06B7FA00266EE2 /* DemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3013DFA1C06B7FA00266EE2 /* DemoViewController.swift */; };
D33C7C801C44E9A800E1687A /* TBEmptyDataSet.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D33C7C7F1C44E9A800E1687A /* TBEmptyDataSet.framework */; };
D33C7C811C44E9A800E1687A /* TBEmptyDataSet.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D33C7C7F1C44E9A800E1687A /* TBEmptyDataSet.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
D3565AA31BFD9449002CFA16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3565AA21BFD9449002CFA16 /* AppDelegate.swift */; };
D3565AA81BFD9449002CFA16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D3565AA61BFD9449002CFA16 /* Main.storyboard */; };
D3565AAA1BFD9449002CFA16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3565AA91BFD9449002CFA16 /* Assets.xcassets */; };
D39EBFCA1C040C040089B394 /* EmptyDataDemoTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39EBFC91C040C040089B394 /* EmptyDataDemoTableViewController.swift */; };
D39EBFCC1C040F220089B394 /* EmptyDataDemoCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39EBFCB1C040F220089B394 /* EmptyDataDemoCollectionViewController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
D33C7C821C44E9A800E1687A /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
D33C7C811C44E9A800E1687A /* TBEmptyDataSet.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
D3013DFA1C06B7FA00266EE2 /* DemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DemoViewController.swift; sourceTree = "<group>"; };
D33C7C7F1C44E9A800E1687A /* TBEmptyDataSet.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = TBEmptyDataSet.framework; path = "/Users/hongxin/Library/Developer/Xcode/DerivedData/TBEmptyDataSet-cgdivxseqtlgnzctplvlotcjtyby/Build/Products/Debug-iphoneos/TBEmptyDataSet.framework"; sourceTree = "<absolute>"; };
D3565A9F1BFD9449002CFA16 /* TBEmptyDataSetExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TBEmptyDataSetExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
D3565AA21BFD9449002CFA16 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D3565AA71BFD9449002CFA16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
D3565AA91BFD9449002CFA16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
D3565AAE1BFD9449002CFA16 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D39EBFC91C040C040089B394 /* EmptyDataDemoTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyDataDemoTableViewController.swift; sourceTree = "<group>"; };
D39EBFCB1C040F220089B394 /* EmptyDataDemoCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyDataDemoCollectionViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D3565A9C1BFD9449002CFA16 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D33C7C801C44E9A800E1687A /* TBEmptyDataSet.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D3565A961BFD9449002CFA16 = {
isa = PBXGroup;
children = (
D33C7C7F1C44E9A800E1687A /* TBEmptyDataSet.framework */,
D3565AA11BFD9449002CFA16 /* Example */,
D3565AA01BFD9449002CFA16 /* Products */,
);
sourceTree = "<group>";
};
D3565AA01BFD9449002CFA16 /* Products */ = {
isa = PBXGroup;
children = (
D3565A9F1BFD9449002CFA16 /* TBEmptyDataSetExample.app */,
);
name = Products;
sourceTree = "<group>";
};
D3565AA11BFD9449002CFA16 /* Example */ = {
isa = PBXGroup;
children = (
D3565AA21BFD9449002CFA16 /* AppDelegate.swift */,
D3013DFA1C06B7FA00266EE2 /* DemoViewController.swift */,
D39EBFC91C040C040089B394 /* EmptyDataDemoTableViewController.swift */,
D39EBFCB1C040F220089B394 /* EmptyDataDemoCollectionViewController.swift */,
D3565AA61BFD9449002CFA16 /* Main.storyboard */,
D3565AA91BFD9449002CFA16 /* Assets.xcassets */,
D3565AAE1BFD9449002CFA16 /* Info.plist */,
);
path = Example;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
D3565A9E1BFD9449002CFA16 /* TBEmptyDataSetExample */ = {
isa = PBXNativeTarget;
buildConfigurationList = D3565AB11BFD9449002CFA16 /* Build configuration list for PBXNativeTarget "TBEmptyDataSetExample" */;
buildPhases = (
D3565A9B1BFD9449002CFA16 /* Sources */,
D3565A9C1BFD9449002CFA16 /* Frameworks */,
D3565A9D1BFD9449002CFA16 /* Resources */,
D3013DFC1C06E0D200266EE2 /* ShellScript */,
D33C7C821C44E9A800E1687A /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = TBEmptyDataSetExample;
productName = TBEmptyDataSet;
productReference = D3565A9F1BFD9449002CFA16 /* TBEmptyDataSetExample.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D3565A971BFD9449002CFA16 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = Teambition;
TargetAttributes = {
D3565A9E1BFD9449002CFA16 = {
CreatedOnToolsVersion = 7.1.1;
LastSwiftMigration = 1020;
};
};
};
buildConfigurationList = D3565A9A1BFD9449002CFA16 /* Build configuration list for PBXProject "TBEmptyDataSetExample" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = D3565A961BFD9449002CFA16;
productRefGroup = D3565AA01BFD9449002CFA16 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D3565A9E1BFD9449002CFA16 /* TBEmptyDataSetExample */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D3565A9D1BFD9449002CFA16 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D3565AAA1BFD9449002CFA16 /* Assets.xcassets in Resources */,
D3565AA81BFD9449002CFA16 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
D3013DFC1C06E0D200266EE2 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D3565A9B1BFD9449002CFA16 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D3565AA31BFD9449002CFA16 /* AppDelegate.swift in Sources */,
D39EBFCA1C040C040089B394 /* EmptyDataDemoTableViewController.swift in Sources */,
D39EBFCC1C040F220089B394 /* EmptyDataDemoCollectionViewController.swift in Sources */,
D3013DFB1C06B7FA00266EE2 /* DemoViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
D3565AA61BFD9449002CFA16 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
D3565AA71BFD9449002CFA16 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
D3565AAF1BFD9449002CFA16 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
D3565AB01BFD9449002CFA16 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D3565AB21BFD9449002CFA16 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = "$(SRCROOT)/Example/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = Teambition.TBEmptyDataSetExample;
PRODUCT_NAME = TBEmptyDataSetExample;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
D3565AB31BFD9449002CFA16 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = "$(SRCROOT)/Example/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = Teambition.TBEmptyDataSetExample;
PRODUCT_NAME = TBEmptyDataSetExample;
SWIFT_VERSION = 5.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D3565A9A1BFD9449002CFA16 /* Build configuration list for PBXProject "TBEmptyDataSetExample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D3565AAF1BFD9449002CFA16 /* Debug */,
D3565AB01BFD9449002CFA16 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D3565AB11BFD9449002CFA16 /* Build configuration list for PBXNativeTarget "TBEmptyDataSetExample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D3565AB21BFD9449002CFA16 /* Debug */,
D3565AB31BFD9449002CFA16 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D3565A971BFD9449002CFA16 /* Project object */;
}
================================================
FILE: TBEmptyDataSetExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:/Users/hongxin/Developer/TBEmptyDataSet/Example/TBEmptyDataSetExample.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: TBEmptyDataSetExample.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/TBEmptyDataSetExample.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: TBEmptyDataSetExample.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>TBEmptyDataSetExample.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>D3565A9E1BFD9449002CFA16</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
================================================
FILE: TBEmptyDataSetExample.xcodeproj/xcuserdata/zetasq.xcuserdatad/xcschemes/TBEmptyDataSetExample.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D3565A9E1BFD9449002CFA16"
BuildableName = "TBEmptyDataSetExample.app"
BlueprintName = "TBEmptyDataSetExample"
ReferencedContainer = "container:TBEmptyDataSetExample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: TBEmptyDataSetExample.xcodeproj/xcuserdata/zetasq.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>TBEmptyDataSetExample.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>D3565A9E1BFD9449002CFA16</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>
gitextract_9vpatnox/
├── .gitignore
├── .swift-version
├── .swiftlint.yml
├── Example/
│ ├── .swiftlint.yml
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── icon-empty-events.imageset/
│ │ │ └── Contents.json
│ │ ├── icon-empty-message.imageset/
│ │ │ └── Contents.json
│ │ ├── icon-empty-photos.imageset/
│ │ │ └── Contents.json
│ │ └── loading.imageset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── Main.storyboard
│ ├── DemoViewController.swift
│ ├── EmptyDataDemoCollectionViewController.swift
│ ├── EmptyDataDemoTableViewController.swift
│ └── Info.plist
├── LICENSE.md
├── README.md
├── TBEmptyDataSet/
│ ├── Constants.swift
│ ├── EmptyDataView.swift
│ ├── Protocols.swift
│ ├── Supporting Files/
│ │ └── Info.plist
│ ├── TBEmptyDataSet.swift
│ └── WeakObjectContainer.swift
├── TBEmptyDataSet.podspec
├── TBEmptyDataSet.xcodeproj/
│ ├── project.pbxproj
│ ├── xcshareddata/
│ │ └── xcschemes/
│ │ └── TBEmptyDataSet.xcscheme
│ └── xcuserdata/
│ ├── hongxin.xcuserdatad/
│ │ └── xcschemes/
│ │ └── xcschememanagement.plist
│ └── zetasq.xcuserdatad/
│ └── xcschemes/
│ └── xcschememanagement.plist
├── TBEmptyDataSet.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
└── TBEmptyDataSetExample.xcodeproj/
├── project.pbxproj
├── project.xcworkspace/
│ └── contents.xcworkspacedata
└── xcuserdata/
├── hongxin.xcuserdatad/
│ └── xcschemes/
│ ├── TBEmptyDataSetExample.xcscheme
│ └── xcschememanagement.plist
└── zetasq.xcuserdatad/
└── xcschemes/
├── TBEmptyDataSetExample.xcscheme
└── xcschememanagement.plist
Condensed preview — 37 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (122K chars).
[
{
"path": ".gitignore",
"chars": 38,
"preview": "TBEmptyDataSet.xcworkspace/xcuserdata\n"
},
{
"path": ".swift-version",
"chars": 4,
"preview": "5.0\n"
},
{
"path": ".swiftlint.yml",
"chars": 835,
"preview": "disabled_rules: # rule identifiers to exclude from running\n - line_length\n - nesting\n - variable_name_min_length\n - "
},
{
"path": "Example/.swiftlint.yml",
"chars": 504,
"preview": "disabled_rules: # rule identifiers to exclude from running\n - line_length\n - nesting\nincluded: # paths to include duri"
},
{
"path": "Example/AppDelegate.swift",
"chars": 826,
"preview": "//\n// AppDelegate.swift\n// TBEmptyDataSetExample\n//\n// Created by 洪鑫 on 15/11/19.\n// Copyright © 2015年 Teambition. A"
},
{
"path": "Example/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1590,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"20x20\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "Example/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "Example/Assets.xcassets/icon-empty-events.imageset/Contents.json",
"chars": 166,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"icon-empty-events.pdf\"\n }\n ],\n \"info\" : {\n "
},
{
"path": "Example/Assets.xcassets/icon-empty-message.imageset/Contents.json",
"chars": 167,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"icon-empty-message.pdf\"\n }\n ],\n \"info\" : {\n"
},
{
"path": "Example/Assets.xcassets/icon-empty-photos.imageset/Contents.json",
"chars": 166,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"icon-empty-photos.pdf\"\n }\n ],\n \"info\" : {\n "
},
{
"path": "Example/Assets.xcassets/loading.imageset/Contents.json",
"chars": 341,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n {\n \"idiom\" : \"universal\",\n "
},
{
"path": "Example/Base.lproj/Main.storyboard",
"chars": 10166,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "Example/DemoViewController.swift",
"chars": 3534,
"preview": "//\n// DemoViewController.swift\n// TBEmptyDataSetExample\n//\n// Created by 洪鑫 on 15/11/26.\n// Copyright © 2015年 Teambi"
},
{
"path": "Example/EmptyDataDemoCollectionViewController.swift",
"chars": 9720,
"preview": "//\n// EmptyDataDemoCollectionViewController.swift\n// TBEmptyDataSetExample\n//\n// Created by 洪鑫 on 15/11/24.\n// Copyr"
},
{
"path": "Example/EmptyDataDemoTableViewController.swift",
"chars": 6076,
"preview": "//\n// EmptyDataDemoTableViewController.swift\n// TBEmptyDataSetExample\n//\n// Created by 洪鑫 on 15/11/24.\n// Copyright "
},
{
"path": "Example/Info.plist",
"chars": 1498,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LICENSE.md",
"chars": 1078,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Teambition\n\nPermission is hereby granted, free of charge, to any person obtain"
},
{
"path": "README.md",
"chars": 3981,
"preview": "# TBEmptyDataSet\nTBEmptyDataSet is an extension of UITableView/UICollectionView's super class, it will display a placeh"
},
{
"path": "TBEmptyDataSet/Constants.swift",
"chars": 1997,
"preview": "//\n// Constants.swift\n// TBEmptyDataSet\n//\n// Created by Xin Hong on 15/11/19.\n// Copyright © 2015年 Teambition. All "
},
{
"path": "TBEmptyDataSet/EmptyDataView.swift",
"chars": 10409,
"preview": "//\n// EmptyDataView.swift\n// TBEmptyDataSet\n//\n// Created by Xin Hong on 15/11/19.\n// Copyright © 2015年 Teambition. "
},
{
"path": "TBEmptyDataSet/Protocols.swift",
"chars": 3501,
"preview": "//\n// Protocols.swift\n// TBEmptyDataSet\n//\n// Created by Xin Hong on 15/11/19.\n// Copyright © 2015年 Teambition. All "
},
{
"path": "TBEmptyDataSet/Supporting Files/Info.plist",
"chars": 808,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "TBEmptyDataSet/TBEmptyDataSet.swift",
"chars": 13091,
"preview": "//\n// TBEmptyDataSet.swift\n// TBEmptyDataSet\n//\n// Created by Xin Hong on 15/11/19.\n// Copyright © 2015年 Teambition."
},
{
"path": "TBEmptyDataSet/WeakObjectContainer.swift",
"chars": 332,
"preview": "//\n// WeakObjectContainer.swift\n// TBEmptyDataSet\n//\n// Created by Xin Hong on 2016/11/4.\n// Copyright © 2016年 Teamb"
},
{
"path": "TBEmptyDataSet.podspec",
"chars": 632,
"preview": "Pod::Spec.new do |s|\n\n s.name = \"TBEmptyDataSet\"\n s.version = \"3.0.2\"\n s.summary = \"An extension of"
},
{
"path": "TBEmptyDataSet.xcodeproj/project.pbxproj",
"chars": 13007,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "TBEmptyDataSet.xcodeproj/xcshareddata/xcschemes/TBEmptyDataSet.xcscheme",
"chars": 2913,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1020\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "TBEmptyDataSet.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 498,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "TBEmptyDataSet.xcodeproj/xcuserdata/zetasq.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 498,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "TBEmptyDataSet.xcworkspace/contents.xcworkspacedata",
"chars": 244,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:TBEmptyDataSet"
},
{
"path": "TBEmptyDataSet.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "TBEmptyDataSetExample.xcodeproj/project.pbxproj",
"chars": 14584,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "TBEmptyDataSetExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 214,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:/Users/hongxin/"
},
{
"path": "TBEmptyDataSetExample.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/TBEmptyDataSetExample.xcscheme",
"chars": 3471,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1020\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "TBEmptyDataSetExample.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 493,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "TBEmptyDataSetExample.xcodeproj/xcuserdata/zetasq.xcuserdatad/xcschemes/TBEmptyDataSetExample.xcscheme",
"chars": 3471,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0730\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "TBEmptyDataSetExample.xcodeproj/xcuserdata/zetasq.xcuserdatad/xcschemes/xcschememanagement.plist",
"chars": 493,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
}
]
About this extraction
This page contains the full source code of the teambition/TBEmptyDataSet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 37 files (109.0 KB), approximately 30.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.