├── Sceenshots
├── screenshot0.png
├── screenshot1.png
└── screenshot2.gif
├── Demo
├── Demo
│ ├── Images.xcassets
│ │ ├── phil.imageset
│ │ │ ├── phil.png
│ │ │ └── Contents.json
│ │ ├── sunnyxx.imageset
│ │ │ ├── 下载.png
│ │ │ └── Contents.json
│ │ ├── doge.imageset
│ │ │ ├── doge@2x.png
│ │ │ └── Contents.json
│ │ ├── sark.imageset
│ │ │ ├── sark@2x.png
│ │ │ └── Contents.json
│ │ ├── sinojerk.imageset
│ │ │ ├── 彪哥副本.png
│ │ │ └── Contents.json
│ │ ├── breaddoge.imageset
│ │ │ ├── dogebread.png
│ │ │ └── Contents.json
│ │ ├── forkingdog.imageset
│ │ │ ├── forkingdog@2x.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── FDAppDelegate.m
│ ├── FDFeedViewController.h
│ ├── FDAppDelegate.h
│ ├── FDFeedCell.h
│ ├── main.m
│ ├── FDFeedEntity.h
│ ├── FDFeedEntity.m
│ ├── Info.plist
│ ├── FDFeedCell.m
│ ├── Base.lproj
│ │ ├── LaunchScreen.xib
│ │ └── Main.storyboard
│ ├── FDFeedViewController.m
│ └── data.json
└── Demo.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── project.pbxproj
├── FDTemplateCell.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── FDTemplateCell.xcscmblueprint
├── FDTemplateLayoutCell
├── FDTemplateLayoutcell
│ ├── FDTemplateLayoutCell.h
│ └── Info.plist
└── FDTemplateLayoutCell.xcodeproj
│ ├── xcshareddata
│ └── xcschemes
│ │ └── FDTemplateLayoutCell.xcscheme
│ └── project.pbxproj
├── .gitignore
├── LICENSE
├── UITableView+FDTemplateLayoutCell.podspec
├── Classes
├── UITableView+FDTemplateLayoutCellDebug.h
├── UITableView+FDKeyedHeightCache.h
├── UITableView+FDTemplateLayoutCellDebug.m
├── UITableView+FDIndexPathHeightCache.h
├── UITableView+FDKeyedHeightCache.m
├── UITableView+FDTemplateLayoutCell.h
├── UITableView+FDIndexPathHeightCache.m
└── UITableView+FDTemplateLayoutCell.m
└── README.md
/Sceenshots/screenshot0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Sceenshots/screenshot0.png
--------------------------------------------------------------------------------
/Sceenshots/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Sceenshots/screenshot1.png
--------------------------------------------------------------------------------
/Sceenshots/screenshot2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Sceenshots/screenshot2.gif
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/phil.imageset/phil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Demo/Demo/Images.xcassets/phil.imageset/phil.png
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/sunnyxx.imageset/下载.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Demo/Demo/Images.xcassets/sunnyxx.imageset/下载.png
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/doge.imageset/doge@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Demo/Demo/Images.xcassets/doge.imageset/doge@2x.png
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/sark.imageset/sark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Demo/Demo/Images.xcassets/sark.imageset/sark@2x.png
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/sinojerk.imageset/彪哥副本.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Demo/Demo/Images.xcassets/sinojerk.imageset/彪哥副本.png
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/breaddoge.imageset/dogebread.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Demo/Demo/Images.xcassets/breaddoge.imageset/dogebread.png
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/forkingdog.imageset/forkingdog@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/forkingdog/UITableView-FDTemplateLayoutCell/HEAD/Demo/Demo/Images.xcassets/forkingdog.imageset/forkingdog@2x.png
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Demo/Demo/FDAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/16.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import "FDAppDelegate.h"
10 |
11 | @implementation FDAppDelegate
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Demo/Demo/FDFeedViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FDFeedViewController.h
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/16.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FDFeedViewController : UITableViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FDTemplateCell.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Demo/Demo/FDAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/16.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FDAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/Demo/Demo/FDFeedCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // FDFeedCell.h
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/17.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "FDFeedEntity.h"
11 |
12 | @interface FDFeedCell : UITableViewCell
13 |
14 | @property (nonatomic, strong) FDFeedEntity *entity;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Demo/Demo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/16.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "FDAppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([FDAppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/doge.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x",
10 | "filename" : "doge@2x.png"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/phil.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x",
10 | "filename" : "phil.png"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/sark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x",
10 | "filename" : "sark@2x.png"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/sunnyxx.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x",
10 | "filename" : "下载.png"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/sinojerk.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x",
10 | "filename" : "彪哥副本.png"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/breaddoge.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x",
10 | "filename" : "dogebread.png"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/forkingdog.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x",
10 | "filename" : "forkingdog@2x.png"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/FDTemplateLayoutCell/FDTemplateLayoutcell/FDTemplateLayoutCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // FDTemplateLayoutCell.h
3 | // FDTemplateLayoutCell
4 | //
5 | // Created by ospreyren on 9/19/15.
6 | //
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for FDTemplateLayoutCell.
12 | FOUNDATION_EXPORT double FDTemplateLayoutCellVersionNumber;
13 |
14 | //! Project version string for FDTemplateLayoutCell.
15 | FOUNDATION_EXPORT const unsigned char FDTemplateLayoutCellVersionString[];
16 |
17 | #import
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 |
20 | # CocoaPods
21 | #
22 | # We recommend against adding the Pods directory to your .gitignore. However
23 | # you should judge for yourself, the pros and cons are mentioned at:
24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
25 | #
26 | #Pods/
27 |
--------------------------------------------------------------------------------
/Demo/Demo/FDFeedEntity.h:
--------------------------------------------------------------------------------
1 | //
2 | // FDFeedEntity.h
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/16.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FDFeedEntity : NSObject
12 |
13 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
14 |
15 | @property (nonatomic, copy, readonly) NSString *identifier;
16 | @property (nonatomic, copy, readonly) NSString *title;
17 | @property (nonatomic, copy, readonly) NSString *content;
18 | @property (nonatomic, copy, readonly) NSString *username;
19 | @property (nonatomic, copy, readonly) NSString *time;
20 | @property (nonatomic, copy, readonly) NSString *imageName;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/Demo/Demo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/Demo/Demo/FDFeedEntity.m:
--------------------------------------------------------------------------------
1 | //
2 | // FDFeedEntity.m
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/16.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import "FDFeedEntity.h"
10 |
11 | @implementation FDFeedEntity
12 |
13 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary
14 | {
15 | self = super.init;
16 | if (self) {
17 | _identifier = [self uniqueIdentifier];
18 | _title = dictionary[@"title"];
19 | _content = dictionary[@"content"];
20 | _username = dictionary[@"username"];
21 | _time = dictionary[@"time"];
22 | _imageName = dictionary[@"imageName"];
23 | }
24 | return self;
25 | }
26 |
27 | - (NSString *)uniqueIdentifier
28 | {
29 | static NSInteger counter = 0;
30 | return [NSString stringWithFormat:@"unique-id-%@", @(counter++)];
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/FDTemplateLayoutCell/FDTemplateLayoutcell/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Demo/Demo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | com.forkingdog.templatelayoutcell.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/UITableView+FDTemplateLayoutCell.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 | s.name = "UITableView+FDTemplateLayoutCell"
4 | s.version = "1.6"
5 | s.summary = "Template auto layout cell for automatically UITableViewCell height calculate, cache and precache"
6 | s.description = "Template auto layout cell for automatically UITableViewCell height calculate, cache and precache. Requires a `self-satisfied` UITableViewCell, using system's `- systemLayoutSizeFittingSize:`, provides heights caching."
7 | s.homepage = "https://github.com/forkingdog/UITableView-FDTemplateLayoutCell"
8 |
9 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
10 | s.license = { :type => "MIT", :file => "LICENSE" }
11 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
12 | s.author = { "forkingdog group" => "https://github.com/forkingdog" }
13 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
14 | s.platform = :ios, "6.0"
15 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
16 | s.source = { :git => "https://github.com/forkingdog/UITableView-FDTemplateLayoutCell.git", :tag => s.version.to_s }
17 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
18 | s.source_files = "Classes/*.{h,m}"
19 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
20 | s.requires_arc = true
21 | end
22 |
--------------------------------------------------------------------------------
/Classes/UITableView+FDTemplateLayoutCellDebug.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import
24 |
25 | @interface UITableView (FDTemplateLayoutCellDebug)
26 |
27 | /// Helps to debug or inspect what is this "FDTemplateLayoutCell" extention doing,
28 | /// turning on to print logs when "creating", "calculating", "precaching" or "hitting cache".
29 | ///
30 | /// Default to NO, log by NSLog.
31 | ///
32 | @property (nonatomic, assign) BOOL fd_debugLogEnabled;
33 |
34 | /// Debug log controlled by "fd_debugLogEnabled".
35 | - (void)fd_debugLog:(NSString *)message;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/Demo/Demo/FDFeedCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // FDFeedCell.m
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/17.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import "FDFeedCell.h"
10 |
11 | @interface FDFeedCell ()
12 |
13 | @property (nonatomic, weak) IBOutlet UILabel *titleLabel;
14 | @property (nonatomic, weak) IBOutlet UILabel *contentLabel;
15 | @property (nonatomic, weak) IBOutlet UIImageView *contentImageView;
16 | @property (nonatomic, weak) IBOutlet UILabel *usernameLabel;
17 | @property (nonatomic, weak) IBOutlet UILabel *timeLabel;
18 |
19 | @end
20 |
21 | @implementation FDFeedCell
22 |
23 | - (void)awakeFromNib
24 | {
25 | [super awakeFromNib];
26 |
27 | // Fix the bug in iOS7 - initial constraints warning
28 | self.contentView.bounds = [UIScreen mainScreen].bounds;
29 | }
30 |
31 | - (void)setEntity:(FDFeedEntity *)entity
32 | {
33 | _entity = entity;
34 |
35 | self.titleLabel.text = entity.title;
36 | self.contentLabel.text = entity.content;
37 | self.contentImageView.image = entity.imageName.length > 0 ? [UIImage imageNamed:entity.imageName] : nil;
38 | self.usernameLabel.text = entity.username;
39 | self.timeLabel.text = entity.time;
40 | }
41 |
42 | // If you are not using auto layout, override this method, enable it by setting
43 | // "fd_enforceFrameLayout" to YES.
44 | - (CGSize)sizeThatFits:(CGSize)size {
45 | CGFloat totalHeight = 0;
46 | totalHeight += [self.titleLabel sizeThatFits:size].height;
47 | totalHeight += [self.contentLabel sizeThatFits:size].height;
48 | totalHeight += [self.contentImageView sizeThatFits:size].height;
49 | totalHeight += [self.usernameLabel sizeThatFits:size].height;
50 | totalHeight += 40; // margins
51 | return CGSizeMake(size.width, totalHeight);
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/FDTemplateCell.xcworkspace/xcshareddata/FDTemplateCell.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "45232C3CDBDF9DB333979E103A0429BCEB54D2EF",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "32d7d9b4-ffb1-4469-8922-27dbf3d99605++9332" : 0,
8 | "45232C3CDBDF9DB333979E103A0429BCEB54D2EF" : 0
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "6569ED7F-B9F6-4B04-BF61-CB6FDE03BD78",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "32d7d9b4-ffb1-4469-8922-27dbf3d99605++9332" : "svn\/iknow",
13 | "45232C3CDBDF9DB333979E103A0429BCEB54D2EF" : "UITableView-FDTemplateLayoutCell"
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "FDTemplateCell",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "FDTemplateCell.xcworkspace",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/svn.baidu.com\/app\/search\/iknow",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "32d7d9b4-ffb1-4469-8922-27dbf3d99605++9332"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/forkingdog\/UITableView-FDTemplateLayoutCell.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "45232C3CDBDF9DB333979E103A0429BCEB54D2EF"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/Classes/UITableView+FDKeyedHeightCache.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import
24 |
25 | @interface FDKeyedHeightCache : NSObject
26 |
27 | - (BOOL)existsHeightForKey:(id)key;
28 | - (void)cacheHeight:(CGFloat)height byKey:(id)key;
29 | - (CGFloat)heightForKey:(id)key;
30 |
31 | // Invalidation
32 | - (void)invalidateHeightForKey:(id)key;
33 | - (void)invalidateAllHeightCache;
34 | @end
35 |
36 | @interface UITableView (FDKeyedHeightCache)
37 |
38 | /// Height cache by key. Generally, you don't need to use it directly.
39 | @property (nonatomic, strong, readonly) FDKeyedHeightCache *fd_keyedHeightCache;
40 | @end
41 |
--------------------------------------------------------------------------------
/Classes/UITableView+FDTemplateLayoutCellDebug.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import "UITableView+FDTemplateLayoutCellDebug.h"
24 | #import
25 |
26 | @implementation UITableView (FDTemplateLayoutCellDebug)
27 |
28 | - (BOOL)fd_debugLogEnabled {
29 | return [objc_getAssociatedObject(self, _cmd) boolValue];
30 | }
31 |
32 | - (void)setFd_debugLogEnabled:(BOOL)debugLogEnabled {
33 | objc_setAssociatedObject(self, @selector(fd_debugLogEnabled), @(debugLogEnabled), OBJC_ASSOCIATION_RETAIN);
34 | }
35 |
36 | - (void)fd_debugLog:(NSString *)message {
37 | if (self.fd_debugLogEnabled) {
38 | NSLog(@"** FDTemplateLayoutCell ** %@", message);
39 | }
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/Classes/UITableView+FDIndexPathHeightCache.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import
24 |
25 | @interface FDIndexPathHeightCache : NSObject
26 |
27 | // Enable automatically if you're using index path driven height cache
28 | @property (nonatomic, assign) BOOL automaticallyInvalidateEnabled;
29 |
30 | // Height cache
31 | - (BOOL)existsHeightAtIndexPath:(NSIndexPath *)indexPath;
32 | - (void)cacheHeight:(CGFloat)height byIndexPath:(NSIndexPath *)indexPath;
33 | - (CGFloat)heightForIndexPath:(NSIndexPath *)indexPath;
34 | - (void)invalidateHeightAtIndexPath:(NSIndexPath *)indexPath;
35 | - (void)invalidateAllHeightCache;
36 |
37 | @end
38 |
39 | @interface UITableView (FDIndexPathHeightCache)
40 | /// Height cache by index path. Generally, you don't need to use it directly.
41 | @property (nonatomic, strong, readonly) FDIndexPathHeightCache *fd_indexPathHeightCache;
42 | @end
43 |
44 | @interface UITableView (FDIndexPathHeightCacheInvalidation)
45 | /// Call this method when you want to reload data but don't want to invalidate
46 | /// all height cache by index path, for example, load more data at the bottom of
47 | /// table view.
48 | - (void)fd_reloadDataWithoutInvalidateIndexPathHeightCache;
49 | @end
50 |
--------------------------------------------------------------------------------
/FDTemplateLayoutCell/FDTemplateLayoutCell.xcodeproj/xcshareddata/xcschemes/FDTemplateLayoutCell.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/Classes/UITableView+FDKeyedHeightCache.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import "UITableView+FDKeyedHeightCache.h"
24 | #import
25 |
26 | @interface FDKeyedHeightCache ()
27 | @property (nonatomic, strong) NSMutableDictionary, NSNumber *> *mutableHeightsByKeyForPortrait;
28 | @property (nonatomic, strong) NSMutableDictionary, NSNumber *> *mutableHeightsByKeyForLandscape;
29 | @end
30 |
31 | @implementation FDKeyedHeightCache
32 |
33 | - (instancetype)init {
34 | self = [super init];
35 | if (self) {
36 | _mutableHeightsByKeyForPortrait = [NSMutableDictionary dictionary];
37 | _mutableHeightsByKeyForLandscape = [NSMutableDictionary dictionary];
38 | }
39 | return self;
40 | }
41 |
42 | - (NSMutableDictionary, NSNumber *> *)mutableHeightsByKeyForCurrentOrientation {
43 | return UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation) ? self.mutableHeightsByKeyForPortrait: self.mutableHeightsByKeyForLandscape;
44 | }
45 |
46 | - (BOOL)existsHeightForKey:(id)key {
47 | NSNumber *number = self.mutableHeightsByKeyForCurrentOrientation[key];
48 | return number && ![number isEqualToNumber:@-1];
49 | }
50 |
51 | - (void)cacheHeight:(CGFloat)height byKey:(id)key {
52 | self.mutableHeightsByKeyForCurrentOrientation[key] = @(height);
53 | }
54 |
55 | - (CGFloat)heightForKey:(id)key {
56 | #if CGFLOAT_IS_DOUBLE
57 | return [self.mutableHeightsByKeyForCurrentOrientation[key] doubleValue];
58 | #else
59 | return [self.mutableHeightsByKeyForCurrentOrientation[key] floatValue];
60 | #endif
61 | }
62 |
63 | - (void)invalidateHeightForKey:(id)key {
64 | [self.mutableHeightsByKeyForPortrait removeObjectForKey:key];
65 | [self.mutableHeightsByKeyForLandscape removeObjectForKey:key];
66 | }
67 |
68 | - (void)invalidateAllHeightCache {
69 | [self.mutableHeightsByKeyForPortrait removeAllObjects];
70 | [self.mutableHeightsByKeyForLandscape removeAllObjects];
71 | }
72 |
73 | @end
74 |
75 | @implementation UITableView (FDKeyedHeightCache)
76 |
77 | - (FDKeyedHeightCache *)fd_keyedHeightCache {
78 | FDKeyedHeightCache *cache = objc_getAssociatedObject(self, _cmd);
79 | if (!cache) {
80 | cache = [FDKeyedHeightCache new];
81 | objc_setAssociatedObject(self, _cmd, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
82 | }
83 | return cache;
84 | }
85 |
86 | @end
87 |
--------------------------------------------------------------------------------
/Demo/Demo/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UITableView-FDTemplateLayoutCell
2 |
3 |
4 | ## Overview
5 | Template auto layout cell for **automatically** UITableViewCell height calculating.
6 |
7 | 
8 |
9 | ## Basic usage
10 |
11 | If you have a **self-satisfied** cell, then all you have to do is:
12 |
13 | ``` objc
14 | #import "UITableView+FDTemplateLayoutCell.h"
15 |
16 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
17 | {
18 | return [tableView fd_heightForCellWithIdentifier:@"reuse identifer" configuration:^(id cell) {
19 | // Configure this cell with data, same as what you've done in "-tableView:cellForRowAtIndexPath:"
20 | // Like:
21 | // cell.entity = self.feedEntities[indexPath.row];
22 | }];
23 | }
24 | ```
25 |
26 | ## Height Caching API
27 |
28 | Since iOS8, `-tableView:heightForRowAtIndexPath:` will be called more times than we expect, we can feel these extra calculations when scrolling. So we provide another API with cache by index path:
29 |
30 | ``` objc
31 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
32 | return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByIndexPath:indexPath configuration:^(id cell) {
33 | // configurations
34 | }];
35 | }
36 | ```
37 |
38 | Or, if your entity has an unique identifier, use cache by key API:
39 |
40 | ``` objc
41 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
42 | Entity *entity = self.entities[indexPath.row];
43 | return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByKey:entity.uid configuration:^(id cell) {
44 | // configurations
45 | }];
46 | }
47 | ```
48 |
49 | ## Frame layout mode
50 |
51 | `FDTemplateLayoutCell` offers 2 modes for asking cell's height.
52 |
53 | 1. Auto layout mode using "-systemLayoutSizeFittingSize:"
54 | 2. Frame layout mode using "-sizeThatFits:"
55 |
56 | Generally, no need to care about modes, it will **automatically** choose a proper mode by whether you have set auto layout constrants on cell's content view. If you want to enforce frame layout mode, enable this property in your cell's configuration block:
57 |
58 | ``` objc
59 | cell.fd_enforceFrameLayout = YES;
60 | ```
61 | And if you're using frame layout mode, you must override `-sizeThatFits:` in your customized cell and return content view's height (separator excluded)
62 |
63 | ```
64 | - (CGSize)sizeThatFits:(CGSize)size {
65 | return CGSizeMake(size.width, A+B+C+D+E+....);
66 | }
67 | ```
68 |
69 | ## Debug log
70 |
71 | Debug log helps to debug or inspect what is this "FDTemplateLayoutCell" extention doing, turning on to print logs when "calculating", "precaching" or "hitting cache".Default to "NO", log by "NSLog".
72 |
73 | ``` objc
74 | self.tableView.fd_debugLogEnabled = YES;
75 | ```
76 |
77 | It will print like this:
78 |
79 | ``` objc
80 | ** FDTemplateLayoutCell ** layout cell created - FDFeedCell
81 | ** FDTemplateLayoutCell ** calculate - [0:0] 233.5
82 | ** FDTemplateLayoutCell ** calculate - [0:1] 155.5
83 | ** FDTemplateLayoutCell ** calculate - [0:2] 258
84 | ** FDTemplateLayoutCell ** calculate - [0:3] 284
85 | ** FDTemplateLayoutCell ** precached - [0:3] 284
86 | ** FDTemplateLayoutCell ** calculate - [0:4] 278.5
87 | ** FDTemplateLayoutCell ** precached - [0:4] 278.5
88 | ** FDTemplateLayoutCell ** hit cache - [0:3] 284
89 | ** FDTemplateLayoutCell ** hit cache - [0:4] 278.5
90 | ** FDTemplateLayoutCell ** hit cache - [0:5] 156
91 | ** FDTemplateLayoutCell ** hit cache - [0:6] 165
92 | ```
93 |
94 | ## About self-satisfied cell
95 |
96 | a fully **self-satisfied** cell is constrainted by auto layout and each edge("top", "left", "bottom", "right") has at least one layout constraint against it. It's the same concept introduced as "self-sizing cell" in iOS8 using auto layout.
97 |
98 | A bad one :( - missing right and bottom
99 | 
100 |
101 | A good one :)
102 | 
103 |
104 | ## Notes
105 |
106 | A template layout cell is created by `-dequeueReusableCellWithIdentifier:` method, it means that you MUST have registered this cell reuse identifier by one of:
107 |
108 | - A prototype cell of UITableView in storyboard.
109 | - Use `-registerNib:forCellReuseIdentifier:`
110 | - Use `-registerClass:forCellReuseIdentifier:`
111 |
112 | ## 如果你在天朝
113 | 可以看这篇中文博客:
114 | [http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/](http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/)
115 |
116 | ## Installation
117 |
118 | Latest version: **1.6**
119 |
120 | ```
121 | pod search UITableView+FDTemplateLayoutCell
122 | ```
123 | If you cannot search out the latest version, try:
124 |
125 | ```
126 | pod setup
127 | ```
128 |
129 | ## Release Notes
130 |
131 | We recommend to use the latest release in cocoapods.
132 |
133 | - 1.6
134 | fix bug in iOS 10
135 |
136 | - 1.4
137 | Refactor, add "cacheByKey" mode, bug fixed
138 |
139 | - 1.3
140 | Frame layout mode, handle cell's accessory view/type
141 |
142 | - 1.2
143 | Precache and auto cache invalidation
144 |
145 | - 1.1
146 | Height cache
147 |
148 | - 1.0
149 | Basic automatically height calculation
150 |
151 | ## License
152 | MIT
153 |
154 |
155 |
--------------------------------------------------------------------------------
/Classes/UITableView+FDTemplateLayoutCell.h:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import
24 | #import "UITableView+FDKeyedHeightCache.h"
25 | #import "UITableView+FDIndexPathHeightCache.h"
26 | #import "UITableView+FDTemplateLayoutCellDebug.h"
27 |
28 | @interface UITableView (FDTemplateLayoutCell)
29 |
30 | /// Access to internal template layout cell for given reuse identifier.
31 | /// Generally, you don't need to know these template layout cells.
32 | ///
33 | /// @param identifier Reuse identifier for cell which must be registered.
34 | ///
35 | - (__kindof UITableViewCell *)fd_templateCellForReuseIdentifier:(NSString *)identifier;
36 |
37 | /// Returns height of cell of type specifed by a reuse identifier and configured
38 | /// by the configuration block.
39 | ///
40 | /// The cell would be layed out on a fixed-width, vertically expanding basis with
41 | /// respect to its dynamic content, using auto layout. Thus, it is imperative that
42 | /// the cell was set up to be self-satisfied, i.e. its content always determines
43 | /// its height given the width is equal to the tableview's.
44 | ///
45 | /// @param identifier A string identifier for retrieving and maintaining template
46 | /// cells with system's "-dequeueReusableCellWithIdentifier:" call.
47 | /// @param configuration An optional block for configuring and providing content
48 | /// to the template cell. The configuration should be minimal for scrolling
49 | /// performance yet sufficient for calculating cell's height.
50 | ///
51 | - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id cell))configuration;
52 |
53 | /// This method does what "-fd_heightForCellWithIdentifier:configuration" does, and
54 | /// calculated height will be cached by its index path, returns a cached height
55 | /// when needed. Therefore lots of extra height calculations could be saved.
56 | ///
57 | /// No need to worry about invalidating cached heights when data source changes, it
58 | /// will be done automatically when you call "-reloadData" or any method that triggers
59 | /// UITableView's reloading.
60 | ///
61 | /// @param indexPath where this cell's height cache belongs.
62 | ///
63 | - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByIndexPath:(NSIndexPath *)indexPath configuration:(void (^)(id cell))configuration;
64 |
65 | /// This method caches height by your model entity's identifier.
66 | /// If your model's changed, call "-invalidateHeightForKey:(id )key" to
67 | /// invalidate cache and re-calculate, it's much cheaper and effective than "cacheByIndexPath".
68 | ///
69 | /// @param key model entity's identifier whose data configures a cell.
70 | ///
71 | - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByKey:(id)key configuration:(void (^)(id cell))configuration;
72 |
73 | @end
74 |
75 | @interface UITableView (FDTemplateLayoutHeaderFooterView)
76 |
77 | /// Returns header or footer view's height that registered in table view with reuse identifier.
78 | ///
79 | /// Use it after calling "-[UITableView registerNib/Class:forHeaderFooterViewReuseIdentifier]",
80 | /// same with "-fd_heightForCellWithIdentifier:configuration:", it will call "-sizeThatFits:" for
81 | /// subclass of UITableViewHeaderFooterView which is not using Auto Layout.
82 | ///
83 | - (CGFloat)fd_heightForHeaderFooterViewWithIdentifier:(NSString *)identifier configuration:(void (^)(id headerFooterView))configuration;
84 |
85 | @end
86 |
87 | @interface UITableViewCell (FDTemplateLayoutCell)
88 |
89 | /// Indicate this is a template layout cell for calculation only.
90 | /// You may need this when there are non-UI side effects when configure a cell.
91 | /// Like:
92 | /// - (void)configureCell:(FooCell *)cell atIndexPath:(NSIndexPath *)indexPath {
93 | /// cell.entity = [self entityAtIndexPath:indexPath];
94 | /// if (!cell.fd_isTemplateLayoutCell) {
95 | /// [self notifySomething]; // non-UI side effects
96 | /// }
97 | /// }
98 | ///
99 | @property (nonatomic, assign) BOOL fd_isTemplateLayoutCell;
100 |
101 | /// Enable to enforce this template layout cell to use "frame layout" rather than "auto layout",
102 | /// and will ask cell's height by calling "-sizeThatFits:", so you must override this method.
103 | /// Use this property only when you want to manually control this template layout cell's height
104 | /// calculation mode, default to NO.
105 | ///
106 | @property (nonatomic, assign) BOOL fd_enforceFrameLayout;
107 |
108 | @end
109 |
--------------------------------------------------------------------------------
/Demo/Demo/FDFeedViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FDFeedViewController.m
3 | // Demo
4 | //
5 | // Created by sunnyxx on 15/4/16.
6 | // Copyright (c) 2015年 forkingdog. All rights reserved.
7 | //
8 |
9 | #import "FDFeedViewController.h"
10 | #import "UITableView+FDTemplateLayoutCell.h"
11 | #import "FDFeedEntity.h"
12 | #import "FDFeedCell.h"
13 |
14 | typedef NS_ENUM(NSInteger, FDSimulatedCacheMode) {
15 | FDSimulatedCacheModeNone = 0,
16 | FDSimulatedCacheModeCacheByIndexPath,
17 | FDSimulatedCacheModeCacheByKey
18 | };
19 |
20 | @interface FDFeedViewController ()
21 | @property (nonatomic, copy) NSArray *prototypeEntitiesFromJSON;
22 | @property (nonatomic, strong) NSMutableArray *feedEntitySections; // 2d array
23 | @property (nonatomic, weak) IBOutlet UISegmentedControl *cacheModeSegmentControl;
24 | @end
25 |
26 | @implementation FDFeedViewController
27 |
28 | - (void)viewDidLoad {
29 | [super viewDidLoad];
30 |
31 | self.tableView.fd_debugLogEnabled = YES;
32 |
33 | // Cache by index path initial
34 | self.cacheModeSegmentControl.selectedSegmentIndex = 1;
35 |
36 | [self buildTestDataThen:^{
37 | self.feedEntitySections = @[].mutableCopy;
38 | [self.feedEntitySections addObject:self.prototypeEntitiesFromJSON.mutableCopy];
39 | [self.tableView reloadData];
40 | }];
41 | }
42 |
43 | - (void)buildTestDataThen:(void (^)(void))then {
44 | // Simulate an async request
45 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
46 |
47 | // Data from `data.json`
48 | NSString *dataFilePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"];
49 | NSData *data = [NSData dataWithContentsOfFile:dataFilePath];
50 | NSDictionary *rootDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
51 | NSArray *feedDicts = rootDict[@"feed"];
52 |
53 | // Convert to `FDFeedEntity`
54 | NSMutableArray *entities = @[].mutableCopy;
55 | [feedDicts enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
56 | [entities addObject:[[FDFeedEntity alloc] initWithDictionary:obj]];
57 | }];
58 | self.prototypeEntitiesFromJSON = entities;
59 |
60 | // Callback
61 | dispatch_async(dispatch_get_main_queue(), ^{
62 | !then ?: then();
63 | });
64 | });
65 | }
66 |
67 | #pragma mark - UITableViewDataSource
68 |
69 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
70 | return self.feedEntitySections.count;
71 | }
72 |
73 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
74 | return [self.feedEntitySections[section] count];
75 | }
76 |
77 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
78 | FDFeedCell *cell = [tableView dequeueReusableCellWithIdentifier:@"FDFeedCell"];
79 | [self configureCell:cell atIndexPath:indexPath];
80 | return cell;
81 | }
82 |
83 | - (void)configureCell:(FDFeedCell *)cell atIndexPath:(NSIndexPath *)indexPath {
84 | cell.fd_enforceFrameLayout = NO; // Enable to use "-sizeThatFits:"
85 | if (indexPath.row % 2 == 0) {
86 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
87 | } else {
88 | cell.accessoryType = UITableViewCellAccessoryCheckmark;
89 | }
90 | cell.entity = self.feedEntitySections[indexPath.section][indexPath.row];
91 | }
92 |
93 | - (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
94 | return @[@"A",@"B",@"C",@"D"];
95 | }
96 |
97 | #pragma mark - UITableViewDelegate
98 |
99 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
100 | FDSimulatedCacheMode mode = self.cacheModeSegmentControl.selectedSegmentIndex;
101 | switch (mode) {
102 | case FDSimulatedCacheModeNone:
103 | return [tableView fd_heightForCellWithIdentifier:@"FDFeedCell" configuration:^(FDFeedCell *cell) {
104 | [self configureCell:cell atIndexPath:indexPath];
105 | }];
106 | case FDSimulatedCacheModeCacheByIndexPath:
107 | return [tableView fd_heightForCellWithIdentifier:@"FDFeedCell" cacheByIndexPath:indexPath configuration:^(FDFeedCell *cell) {
108 | [self configureCell:cell atIndexPath:indexPath];
109 | }];
110 | case FDSimulatedCacheModeCacheByKey: {
111 | FDFeedEntity *entity = self.feedEntitySections[indexPath.section][indexPath.row];
112 |
113 | return [tableView fd_heightForCellWithIdentifier:@"FDFeedCell" cacheByKey:entity.identifier configuration:^(FDFeedCell *cell) {
114 | [self configureCell:cell atIndexPath:indexPath];
115 | }];
116 | };
117 | default:
118 | break;
119 | }
120 | }
121 |
122 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
123 | if (editingStyle == UITableViewCellEditingStyleDelete) {
124 | NSMutableArray *mutableEntities = self.feedEntitySections[indexPath.section];
125 | [mutableEntities removeObjectAtIndex:indexPath.row];
126 | [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
127 | }
128 | }
129 |
130 | #pragma mark - Actions
131 |
132 | - (IBAction)refreshControlAction:(UIRefreshControl *)sender {
133 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
134 | [self.feedEntitySections removeAllObjects];
135 | [self.feedEntitySections addObject:self.prototypeEntitiesFromJSON.mutableCopy];
136 | [self.tableView reloadData];
137 | [sender endRefreshing];
138 | });
139 | }
140 |
141 | - (IBAction)rightNavigationItemAction:(id)sender {
142 | [[[UIActionSheet alloc]
143 | initWithTitle:@"Actions"
144 | delegate:self
145 | cancelButtonTitle:@"Cancel"
146 | destructiveButtonTitle:nil
147 | otherButtonTitles:
148 | @"Insert a row",
149 | @"Insert a section",
150 | @"Delete a section", nil]
151 | showInView:self.view];
152 | }
153 |
154 | - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
155 | SEL selectors[] = {
156 | @selector(insertRow),
157 | @selector(insertSection),
158 | @selector(deleteSection)
159 | };
160 |
161 | if (buttonIndex < sizeof(selectors) / sizeof(SEL)) {
162 | void(*imp)(id, SEL) = (typeof(imp))[self methodForSelector:selectors[buttonIndex]];
163 | imp(self, selectors[buttonIndex]);
164 | }
165 | }
166 |
167 | - (FDFeedEntity *)randomEntity {
168 | NSUInteger randomNumber = arc4random_uniform((int32_t)self.prototypeEntitiesFromJSON.count);
169 | FDFeedEntity *randomEntity = self.prototypeEntitiesFromJSON[randomNumber];
170 | return randomEntity;
171 | }
172 |
173 | - (void)insertRow {
174 | if (self.feedEntitySections.count == 0) {
175 | [self insertSection];
176 | } else {
177 | [self.feedEntitySections[0] insertObject:self.randomEntity atIndex:0];
178 | NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
179 | [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
180 | }
181 | }
182 |
183 | - (void)insertSection {
184 | [self.feedEntitySections insertObject:@[self.randomEntity].mutableCopy atIndex:0];
185 | [self.tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
186 | }
187 |
188 | - (void)deleteSection {
189 | if (self.feedEntitySections.count > 0) {
190 | [self.feedEntitySections removeObjectAtIndex:0];
191 | [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic];
192 | }
193 | }
194 |
195 | @end
196 |
--------------------------------------------------------------------------------
/Classes/UITableView+FDIndexPathHeightCache.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import "UITableView+FDIndexPathHeightCache.h"
24 | #import
25 |
26 | typedef NSMutableArray *> FDIndexPathHeightsBySection;
27 |
28 | @interface FDIndexPathHeightCache ()
29 | @property (nonatomic, strong) FDIndexPathHeightsBySection *heightsBySectionForPortrait;
30 | @property (nonatomic, strong) FDIndexPathHeightsBySection *heightsBySectionForLandscape;
31 | @end
32 |
33 | @implementation FDIndexPathHeightCache
34 |
35 | - (instancetype)init {
36 | self = [super init];
37 | if (self) {
38 | _heightsBySectionForPortrait = [NSMutableArray array];
39 | _heightsBySectionForLandscape = [NSMutableArray array];
40 | }
41 | return self;
42 | }
43 |
44 | - (FDIndexPathHeightsBySection *)heightsBySectionForCurrentOrientation {
45 | return UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation) ? self.heightsBySectionForPortrait: self.heightsBySectionForLandscape;
46 | }
47 |
48 | - (void)enumerateAllOrientationsUsingBlock:(void (^)(FDIndexPathHeightsBySection *heightsBySection))block {
49 | block(self.heightsBySectionForPortrait);
50 | block(self.heightsBySectionForLandscape);
51 | }
52 |
53 | - (BOOL)existsHeightAtIndexPath:(NSIndexPath *)indexPath {
54 | [self buildCachesAtIndexPathsIfNeeded:@[indexPath]];
55 | NSNumber *number = self.heightsBySectionForCurrentOrientation[indexPath.section][indexPath.row];
56 | return ![number isEqualToNumber:@-1];
57 | }
58 |
59 | - (void)cacheHeight:(CGFloat)height byIndexPath:(NSIndexPath *)indexPath {
60 | self.automaticallyInvalidateEnabled = YES;
61 | [self buildCachesAtIndexPathsIfNeeded:@[indexPath]];
62 | self.heightsBySectionForCurrentOrientation[indexPath.section][indexPath.row] = @(height);
63 | }
64 |
65 | - (CGFloat)heightForIndexPath:(NSIndexPath *)indexPath {
66 | [self buildCachesAtIndexPathsIfNeeded:@[indexPath]];
67 | NSNumber *number = self.heightsBySectionForCurrentOrientation[indexPath.section][indexPath.row];
68 | #if CGFLOAT_IS_DOUBLE
69 | return number.doubleValue;
70 | #else
71 | return number.floatValue;
72 | #endif
73 | }
74 |
75 | - (void)invalidateHeightAtIndexPath:(NSIndexPath *)indexPath {
76 | [self buildCachesAtIndexPathsIfNeeded:@[indexPath]];
77 | [self enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
78 | heightsBySection[indexPath.section][indexPath.row] = @-1;
79 | }];
80 | }
81 |
82 | - (void)invalidateAllHeightCache {
83 | [self enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
84 | [heightsBySection removeAllObjects];
85 | }];
86 | }
87 |
88 | - (void)buildCachesAtIndexPathsIfNeeded:(NSArray *)indexPaths {
89 | // Build every section array or row array which is smaller than given index path.
90 | [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
91 | [self buildSectionsIfNeeded:indexPath.section];
92 | [self buildRowsIfNeeded:indexPath.row inExistSection:indexPath.section];
93 | }];
94 | }
95 |
96 | - (void)buildSectionsIfNeeded:(NSInteger)targetSection {
97 | [self enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
98 | for (NSInteger section = 0; section <= targetSection; ++section) {
99 | if (section >= heightsBySection.count) {
100 | heightsBySection[section] = [NSMutableArray array];
101 | }
102 | }
103 | }];
104 | }
105 |
106 | - (void)buildRowsIfNeeded:(NSInteger)targetRow inExistSection:(NSInteger)section {
107 | [self enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
108 | NSMutableArray *heightsByRow = heightsBySection[section];
109 | for (NSInteger row = 0; row <= targetRow; ++row) {
110 | if (row >= heightsByRow.count) {
111 | heightsByRow[row] = @-1;
112 | }
113 | }
114 | }];
115 | }
116 |
117 | @end
118 |
119 | @implementation UITableView (FDIndexPathHeightCache)
120 |
121 | - (FDIndexPathHeightCache *)fd_indexPathHeightCache {
122 | FDIndexPathHeightCache *cache = objc_getAssociatedObject(self, _cmd);
123 | if (!cache) {
124 | cache = [FDIndexPathHeightCache new];
125 | objc_setAssociatedObject(self, _cmd, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
126 | }
127 | return cache;
128 | }
129 |
130 | @end
131 |
132 | // We just forward primary call, in crash report, top most method in stack maybe FD's,
133 | // but it's really not our bug, you should check whether your table view's data source and
134 | // displaying cells are not matched when reloading.
135 | static void __FD_TEMPLATE_LAYOUT_CELL_PRIMARY_CALL_IF_CRASH_NOT_OUR_BUG__(void (^callout)(void)) {
136 | callout();
137 | }
138 | #define FDPrimaryCall(...) do {__FD_TEMPLATE_LAYOUT_CELL_PRIMARY_CALL_IF_CRASH_NOT_OUR_BUG__(^{__VA_ARGS__});} while(0)
139 |
140 | @implementation UITableView (FDIndexPathHeightCacheInvalidation)
141 |
142 | - (void)fd_reloadDataWithoutInvalidateIndexPathHeightCache {
143 | FDPrimaryCall([self fd_reloadData];);
144 | }
145 |
146 | + (void)load {
147 | // All methods that trigger height cache's invalidation
148 | SEL selectors[] = {
149 | @selector(reloadData),
150 | @selector(insertSections:withRowAnimation:),
151 | @selector(deleteSections:withRowAnimation:),
152 | @selector(reloadSections:withRowAnimation:),
153 | @selector(moveSection:toSection:),
154 | @selector(insertRowsAtIndexPaths:withRowAnimation:),
155 | @selector(deleteRowsAtIndexPaths:withRowAnimation:),
156 | @selector(reloadRowsAtIndexPaths:withRowAnimation:),
157 | @selector(moveRowAtIndexPath:toIndexPath:)
158 | };
159 |
160 | for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
161 | SEL originalSelector = selectors[index];
162 | SEL swizzledSelector = NSSelectorFromString([@"fd_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
163 | Method originalMethod = class_getInstanceMethod(self, originalSelector);
164 | Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
165 | method_exchangeImplementations(originalMethod, swizzledMethod);
166 | }
167 | }
168 |
169 | - (void)fd_reloadData {
170 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
171 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
172 | [heightsBySection removeAllObjects];
173 | }];
174 | }
175 | FDPrimaryCall([self fd_reloadData];);
176 | }
177 |
178 | - (void)fd_insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation {
179 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
180 | [sections enumerateIndexesUsingBlock:^(NSUInteger section, BOOL *stop) {
181 | [self.fd_indexPathHeightCache buildSectionsIfNeeded:section];
182 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
183 | [heightsBySection insertObject:[NSMutableArray array] atIndex:section];
184 | }];
185 | }];
186 | }
187 | FDPrimaryCall([self fd_insertSections:sections withRowAnimation:animation];);
188 | }
189 |
190 | - (void)fd_deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation {
191 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
192 | [sections enumerateIndexesUsingBlock:^(NSUInteger section, BOOL *stop) {
193 | [self.fd_indexPathHeightCache buildSectionsIfNeeded:section];
194 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
195 | [heightsBySection removeObjectAtIndex:section];
196 | }];
197 | }];
198 | }
199 | FDPrimaryCall([self fd_deleteSections:sections withRowAnimation:animation];);
200 | }
201 |
202 | - (void)fd_reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation {
203 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
204 | [sections enumerateIndexesUsingBlock: ^(NSUInteger section, BOOL *stop) {
205 | [self.fd_indexPathHeightCache buildSectionsIfNeeded:section];
206 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
207 | [heightsBySection[section] removeAllObjects];
208 | }];
209 |
210 | }];
211 | }
212 | FDPrimaryCall([self fd_reloadSections:sections withRowAnimation:animation];);
213 | }
214 |
215 | - (void)fd_moveSection:(NSInteger)section toSection:(NSInteger)newSection {
216 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
217 | [self.fd_indexPathHeightCache buildSectionsIfNeeded:section];
218 | [self.fd_indexPathHeightCache buildSectionsIfNeeded:newSection];
219 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
220 | [heightsBySection exchangeObjectAtIndex:section withObjectAtIndex:newSection];
221 | }];
222 | }
223 | FDPrimaryCall([self fd_moveSection:section toSection:newSection];);
224 | }
225 |
226 | - (void)fd_insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation {
227 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
228 | [self.fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded:indexPaths];
229 | [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
230 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
231 | [heightsBySection[indexPath.section] insertObject:@-1 atIndex:indexPath.row];
232 | }];
233 | }];
234 | }
235 | FDPrimaryCall([self fd_insertRowsAtIndexPaths:indexPaths withRowAnimation:animation];);
236 | }
237 |
238 | - (void)fd_deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation {
239 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
240 | [self.fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded:indexPaths];
241 |
242 | NSMutableDictionary *mutableIndexSetsToRemove = [NSMutableDictionary dictionary];
243 | [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
244 | NSMutableIndexSet *mutableIndexSet = mutableIndexSetsToRemove[@(indexPath.section)];
245 | if (!mutableIndexSet) {
246 | mutableIndexSet = [NSMutableIndexSet indexSet];
247 | mutableIndexSetsToRemove[@(indexPath.section)] = mutableIndexSet;
248 | }
249 | [mutableIndexSet addIndex:indexPath.row];
250 | }];
251 |
252 | [mutableIndexSetsToRemove enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSIndexSet *indexSet, BOOL *stop) {
253 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
254 | [heightsBySection[key.integerValue] removeObjectsAtIndexes:indexSet];
255 | }];
256 | }];
257 | }
258 | FDPrimaryCall([self fd_deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation];);
259 | }
260 |
261 | - (void)fd_reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation {
262 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
263 | [self.fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded:indexPaths];
264 | [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) {
265 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
266 | heightsBySection[indexPath.section][indexPath.row] = @-1;
267 | }];
268 | }];
269 | }
270 | FDPrimaryCall([self fd_reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation];);
271 | }
272 |
273 | - (void)fd_moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
274 | if (self.fd_indexPathHeightCache.automaticallyInvalidateEnabled) {
275 | [self.fd_indexPathHeightCache buildCachesAtIndexPathsIfNeeded:@[sourceIndexPath, destinationIndexPath]];
276 | [self.fd_indexPathHeightCache enumerateAllOrientationsUsingBlock:^(FDIndexPathHeightsBySection *heightsBySection) {
277 | NSMutableArray *sourceRows = heightsBySection[sourceIndexPath.section];
278 | NSMutableArray *destinationRows = heightsBySection[destinationIndexPath.section];
279 | NSNumber *sourceValue = sourceRows[sourceIndexPath.row];
280 | NSNumber *destinationValue = destinationRows[destinationIndexPath.row];
281 | sourceRows[sourceIndexPath.row] = destinationValue;
282 | destinationRows[destinationIndexPath.row] = sourceValue;
283 | }];
284 | }
285 | FDPrimaryCall([self fd_moveRowAtIndexPath:sourceIndexPath toIndexPath:destinationIndexPath];);
286 | }
287 |
288 | @end
289 |
--------------------------------------------------------------------------------
/Classes/UITableView+FDTemplateLayoutCell.m:
--------------------------------------------------------------------------------
1 | // The MIT License (MIT)
2 | //
3 | // Copyright (c) 2015-2016 forkingdog ( https://github.com/forkingdog )
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in all
13 | // copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | // SOFTWARE.
22 |
23 | #import "UITableView+FDTemplateLayoutCell.h"
24 | #import
25 |
26 | @implementation UITableView (FDTemplateLayoutCell)
27 |
28 | - (CGFloat)fd_systemFittingHeightForConfiguratedCell:(UITableViewCell *)cell {
29 | CGFloat contentViewWidth = CGRectGetWidth(self.frame);
30 |
31 | CGRect cellBounds = cell.bounds;
32 | cellBounds.size.width = contentViewWidth;
33 | cell.bounds = cellBounds;
34 |
35 | CGFloat rightSystemViewsWidth = 0.0;
36 | for (UIView *view in self.subviews) {
37 | if ([view isKindOfClass:NSClassFromString(@"UITableViewIndex")]) {
38 | rightSystemViewsWidth = CGRectGetWidth(view.frame);
39 | break;
40 | }
41 | }
42 |
43 | // If a cell has accessory view or system accessory type, its content view's width is smaller
44 | // than cell's by some fixed values.
45 | if (cell.accessoryView) {
46 | rightSystemViewsWidth += 16 + CGRectGetWidth(cell.accessoryView.frame);
47 | } else {
48 | static const CGFloat systemAccessoryWidths[] = {
49 | [UITableViewCellAccessoryNone] = 0,
50 | [UITableViewCellAccessoryDisclosureIndicator] = 34,
51 | [UITableViewCellAccessoryDetailDisclosureButton] = 68,
52 | [UITableViewCellAccessoryCheckmark] = 40,
53 | [UITableViewCellAccessoryDetailButton] = 48
54 | };
55 | rightSystemViewsWidth += systemAccessoryWidths[cell.accessoryType];
56 | }
57 |
58 | if ([UIScreen mainScreen].scale >= 3 && [UIScreen mainScreen].bounds.size.width >= 414) {
59 | rightSystemViewsWidth += 4;
60 | }
61 |
62 | contentViewWidth -= rightSystemViewsWidth;
63 |
64 |
65 | // If not using auto layout, you have to override "-sizeThatFits:" to provide a fitting size by yourself.
66 | // This is the same height calculation passes used in iOS8 self-sizing cell's implementation.
67 | //
68 | // 1. Try "- systemLayoutSizeFittingSize:" first. (skip this step if 'fd_enforceFrameLayout' set to YES.)
69 | // 2. Warning once if step 1 still returns 0 when using AutoLayout
70 | // 3. Try "- sizeThatFits:" if step 1 returns 0
71 | // 4. Use a valid height or default row height (44) if not exist one
72 |
73 | CGFloat fittingHeight = 0;
74 |
75 | if (!cell.fd_enforceFrameLayout && contentViewWidth > 0) {
76 | // Add a hard width constraint to make dynamic content views (like labels) expand vertically instead
77 | // of growing horizontally, in a flow-layout manner.
78 | NSLayoutConstraint *widthFenceConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:contentViewWidth];
79 |
80 | // [bug fix] after iOS 10.3, Auto Layout engine will add an additional 0 width constraint onto cell's content view, to avoid that, we add constraints to content view's left, right, top and bottom.
81 | static BOOL isSystemVersionEqualOrGreaterThen10_2 = NO;
82 | static dispatch_once_t onceToken;
83 | dispatch_once(&onceToken, ^{
84 | isSystemVersionEqualOrGreaterThen10_2 = [UIDevice.currentDevice.systemVersion compare:@"10.2" options:NSNumericSearch] != NSOrderedAscending;
85 | });
86 |
87 | NSArray *edgeConstraints;
88 | if (isSystemVersionEqualOrGreaterThen10_2) {
89 | // To avoid confilicts, make width constraint softer than required (1000)
90 | widthFenceConstraint.priority = UILayoutPriorityRequired - 1;
91 |
92 | // Build edge constraints
93 | NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
94 | NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeRight multiplier:1.0 constant:-rightSystemViewsWidth];
95 | NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
96 | NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
97 | edgeConstraints = @[leftConstraint, rightConstraint, topConstraint, bottomConstraint];
98 | [cell addConstraints:edgeConstraints];
99 | }
100 |
101 | [cell.contentView addConstraint:widthFenceConstraint];
102 |
103 | // Auto layout engine does its math
104 | fittingHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
105 |
106 | // Clean-ups
107 | [cell.contentView removeConstraint:widthFenceConstraint];
108 | if (isSystemVersionEqualOrGreaterThen10_2) {
109 | [cell removeConstraints:edgeConstraints];
110 | }
111 |
112 | [self fd_debugLog:[NSString stringWithFormat:@"calculate using system fitting size (AutoLayout) - %@", @(fittingHeight)]];
113 | }
114 |
115 | if (fittingHeight == 0) {
116 | #if DEBUG
117 | // Warn if using AutoLayout but get zero height.
118 | if (cell.contentView.constraints.count > 0) {
119 | if (!objc_getAssociatedObject(self, _cmd)) {
120 | NSLog(@"[FDTemplateLayoutCell] Warning once only: Cannot get a proper cell height (now 0) from '- systemFittingSize:'(AutoLayout). You should check how constraints are built in cell, making it into 'self-sizing' cell.");
121 | objc_setAssociatedObject(self, _cmd, @YES, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
122 | }
123 | }
124 | #endif
125 | // Try '- sizeThatFits:' for frame layout.
126 | // Note: fitting height should not include separator view.
127 | fittingHeight = [cell sizeThatFits:CGSizeMake(contentViewWidth, 0)].height;
128 |
129 | [self fd_debugLog:[NSString stringWithFormat:@"calculate using sizeThatFits - %@", @(fittingHeight)]];
130 | }
131 |
132 | // Still zero height after all above.
133 | if (fittingHeight == 0) {
134 | // Use default row height.
135 | fittingHeight = 44;
136 | }
137 |
138 | // Add 1px extra space for separator line if needed, simulating default UITableViewCell.
139 | if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
140 | fittingHeight += 1.0 / [UIScreen mainScreen].scale;
141 | }
142 |
143 | return fittingHeight;
144 | }
145 |
146 | - (__kindof UITableViewCell *)fd_templateCellForReuseIdentifier:(NSString *)identifier {
147 | NSAssert(identifier.length > 0, @"Expect a valid identifier - %@", identifier);
148 |
149 | NSMutableDictionary *templateCellsByIdentifiers = objc_getAssociatedObject(self, _cmd);
150 | if (!templateCellsByIdentifiers) {
151 | templateCellsByIdentifiers = @{}.mutableCopy;
152 | objc_setAssociatedObject(self, _cmd, templateCellsByIdentifiers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
153 | }
154 |
155 | UITableViewCell *templateCell = templateCellsByIdentifiers[identifier];
156 |
157 | if (!templateCell) {
158 | templateCell = [self dequeueReusableCellWithIdentifier:identifier];
159 | NSAssert(templateCell != nil, @"Cell must be registered to table view for identifier - %@", identifier);
160 | templateCell.fd_isTemplateLayoutCell = YES;
161 | templateCell.contentView.translatesAutoresizingMaskIntoConstraints = NO;
162 | templateCellsByIdentifiers[identifier] = templateCell;
163 | [self fd_debugLog:[NSString stringWithFormat:@"layout cell created - %@", identifier]];
164 | }
165 |
166 | return templateCell;
167 | }
168 |
169 | - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id cell))configuration {
170 | if (!identifier) {
171 | return 0;
172 | }
173 |
174 | UITableViewCell *templateLayoutCell = [self fd_templateCellForReuseIdentifier:identifier];
175 |
176 | // Manually calls to ensure consistent behavior with actual cells. (that are displayed on screen)
177 | [templateLayoutCell prepareForReuse];
178 |
179 | // Customize and provide content for our template cell.
180 | if (configuration) {
181 | configuration(templateLayoutCell);
182 | }
183 |
184 | return [self fd_systemFittingHeightForConfiguratedCell:templateLayoutCell];
185 | }
186 |
187 | - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByIndexPath:(NSIndexPath *)indexPath configuration:(void (^)(id cell))configuration {
188 | if (!identifier || !indexPath) {
189 | return 0;
190 | }
191 |
192 | // Hit cache
193 | if ([self.fd_indexPathHeightCache existsHeightAtIndexPath:indexPath]) {
194 | [self fd_debugLog:[NSString stringWithFormat:@"hit cache by index path[%@:%@] - %@", @(indexPath.section), @(indexPath.row), @([self.fd_indexPathHeightCache heightForIndexPath:indexPath])]];
195 | return [self.fd_indexPathHeightCache heightForIndexPath:indexPath];
196 | }
197 |
198 | CGFloat height = [self fd_heightForCellWithIdentifier:identifier configuration:configuration];
199 | [self.fd_indexPathHeightCache cacheHeight:height byIndexPath:indexPath];
200 | [self fd_debugLog:[NSString stringWithFormat: @"cached by index path[%@:%@] - %@", @(indexPath.section), @(indexPath.row), @(height)]];
201 |
202 | return height;
203 | }
204 |
205 | - (CGFloat)fd_heightForCellWithIdentifier:(NSString *)identifier cacheByKey:(id)key configuration:(void (^)(id cell))configuration {
206 | if (!identifier || !key) {
207 | return 0;
208 | }
209 |
210 | // Hit cache
211 | if ([self.fd_keyedHeightCache existsHeightForKey:key]) {
212 | CGFloat cachedHeight = [self.fd_keyedHeightCache heightForKey:key];
213 | [self fd_debugLog:[NSString stringWithFormat:@"hit cache by key[%@] - %@", key, @(cachedHeight)]];
214 | return cachedHeight;
215 | }
216 |
217 | CGFloat height = [self fd_heightForCellWithIdentifier:identifier configuration:configuration];
218 | [self.fd_keyedHeightCache cacheHeight:height byKey:key];
219 | [self fd_debugLog:[NSString stringWithFormat:@"cached by key[%@] - %@", key, @(height)]];
220 |
221 | return height;
222 | }
223 |
224 | @end
225 |
226 | @implementation UITableView (FDTemplateLayoutHeaderFooterView)
227 |
228 | - (__kindof UITableViewHeaderFooterView *)fd_templateHeaderFooterViewForReuseIdentifier:(NSString *)identifier {
229 | NSAssert(identifier.length > 0, @"Expect a valid identifier - %@", identifier);
230 |
231 | NSMutableDictionary *templateHeaderFooterViews = objc_getAssociatedObject(self, _cmd);
232 | if (!templateHeaderFooterViews) {
233 | templateHeaderFooterViews = @{}.mutableCopy;
234 | objc_setAssociatedObject(self, _cmd, templateHeaderFooterViews, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
235 | }
236 |
237 | UITableViewHeaderFooterView *templateHeaderFooterView = templateHeaderFooterViews[identifier];
238 |
239 | if (!templateHeaderFooterView) {
240 | templateHeaderFooterView = [self dequeueReusableHeaderFooterViewWithIdentifier:identifier];
241 | NSAssert(templateHeaderFooterView != nil, @"HeaderFooterView must be registered to table view for identifier - %@", identifier);
242 | templateHeaderFooterView.contentView.translatesAutoresizingMaskIntoConstraints = NO;
243 | templateHeaderFooterViews[identifier] = templateHeaderFooterView;
244 | [self fd_debugLog:[NSString stringWithFormat:@"layout header footer view created - %@", identifier]];
245 | }
246 |
247 | return templateHeaderFooterView;
248 | }
249 |
250 | - (CGFloat)fd_heightForHeaderFooterViewWithIdentifier:(NSString *)identifier configuration:(void (^)(id))configuration {
251 | UITableViewHeaderFooterView *templateHeaderFooterView = [self fd_templateHeaderFooterViewForReuseIdentifier:identifier];
252 |
253 | NSLayoutConstraint *widthFenceConstraint = [NSLayoutConstraint constraintWithItem:templateHeaderFooterView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:CGRectGetWidth(self.frame)];
254 | [templateHeaderFooterView addConstraint:widthFenceConstraint];
255 | CGFloat fittingHeight = [templateHeaderFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
256 | [templateHeaderFooterView removeConstraint:widthFenceConstraint];
257 |
258 | if (fittingHeight == 0) {
259 | fittingHeight = [templateHeaderFooterView sizeThatFits:CGSizeMake(CGRectGetWidth(self.frame), 0)].height;
260 | }
261 |
262 | return fittingHeight;
263 | }
264 |
265 | @end
266 |
267 | @implementation UITableViewCell (FDTemplateLayoutCell)
268 |
269 | - (BOOL)fd_isTemplateLayoutCell {
270 | return [objc_getAssociatedObject(self, _cmd) boolValue];
271 | }
272 |
273 | - (void)setFd_isTemplateLayoutCell:(BOOL)isTemplateLayoutCell {
274 | objc_setAssociatedObject(self, @selector(fd_isTemplateLayoutCell), @(isTemplateLayoutCell), OBJC_ASSOCIATION_RETAIN);
275 | }
276 |
277 | - (BOOL)fd_enforceFrameLayout {
278 | return [objc_getAssociatedObject(self, _cmd) boolValue];
279 | }
280 |
281 | - (void)setFd_enforceFrameLayout:(BOOL)enforceFrameLayout {
282 | objc_setAssociatedObject(self, @selector(fd_enforceFrameLayout), @(enforceFrameLayout), OBJC_ASSOCIATION_RETAIN);
283 | }
284 |
285 | @end
286 |
--------------------------------------------------------------------------------
/Demo/Demo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
54 |
60 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/FDTemplateLayoutCell/FDTemplateLayoutCell.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 485022131C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4850220D1C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 485022141C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4850220E1C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.m */; };
12 | 485022151C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4850220F1C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.h */; settings = {ATTRIBUTES = (Public, ); }; };
13 | 485022161C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 485022101C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.m */; };
14 | 485022171C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = 485022111C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.h */; settings = {ATTRIBUTES = (Public, ); }; };
15 | 485022181C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 485022121C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.m */; };
16 | E19608D11BAD53AF00BDCBBE /* FDTemplateLayoutCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E19608D01BAD53AF00BDCBBE /* FDTemplateLayoutCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
17 | E19608E01BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E19608DE1BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.h */; settings = {ATTRIBUTES = (Public, ); }; };
18 | E19608E11BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E19608DF1BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.m */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXFileReference section */
22 | 4850220D1C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDIndexPathHeightCache.h"; sourceTree = ""; };
23 | 4850220E1C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDIndexPathHeightCache.m"; sourceTree = ""; };
24 | 4850220F1C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDKeyedHeightCache.h"; sourceTree = ""; };
25 | 485022101C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDKeyedHeightCache.m"; sourceTree = ""; };
26 | 485022111C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDTemplateLayoutCellDebug.h"; sourceTree = ""; };
27 | 485022121C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDTemplateLayoutCellDebug.m"; sourceTree = ""; };
28 | E19608CD1BAD53AF00BDCBBE /* FDTemplateLayoutCell.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FDTemplateLayoutCell.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29 | E19608D01BAD53AF00BDCBBE /* FDTemplateLayoutCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FDTemplateLayoutCell.h; sourceTree = ""; };
30 | E19608D21BAD53AF00BDCBBE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
31 | E19608DE1BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDTemplateLayoutCell.h"; sourceTree = ""; };
32 | E19608DF1BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDTemplateLayoutCell.m"; sourceTree = ""; };
33 | /* End PBXFileReference section */
34 |
35 | /* Begin PBXFrameworksBuildPhase section */
36 | E19608C91BAD53AF00BDCBBE /* Frameworks */ = {
37 | isa = PBXFrameworksBuildPhase;
38 | buildActionMask = 2147483647;
39 | files = (
40 | );
41 | runOnlyForDeploymentPostprocessing = 0;
42 | };
43 | /* End PBXFrameworksBuildPhase section */
44 |
45 | /* Begin PBXGroup section */
46 | E19608C31BAD53AE00BDCBBE = {
47 | isa = PBXGroup;
48 | children = (
49 | E19608DD1BAD54EB00BDCBBE /* Classes */,
50 | E19608CF1BAD53AF00BDCBBE /* FDTemplateLayoutCell */,
51 | E19608CE1BAD53AF00BDCBBE /* Products */,
52 | );
53 | sourceTree = "";
54 | };
55 | E19608CE1BAD53AF00BDCBBE /* Products */ = {
56 | isa = PBXGroup;
57 | children = (
58 | E19608CD1BAD53AF00BDCBBE /* FDTemplateLayoutCell.framework */,
59 | );
60 | name = Products;
61 | sourceTree = "";
62 | };
63 | E19608CF1BAD53AF00BDCBBE /* FDTemplateLayoutCell */ = {
64 | isa = PBXGroup;
65 | children = (
66 | E19608D01BAD53AF00BDCBBE /* FDTemplateLayoutCell.h */,
67 | E19608D21BAD53AF00BDCBBE /* Info.plist */,
68 | );
69 | path = FDTemplateLayoutCell;
70 | sourceTree = "";
71 | };
72 | E19608DD1BAD54EB00BDCBBE /* Classes */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 4850220D1C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.h */,
76 | 4850220E1C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.m */,
77 | 4850220F1C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.h */,
78 | 485022101C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.m */,
79 | 485022111C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.h */,
80 | 485022121C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.m */,
81 | E19608DE1BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.h */,
82 | E19608DF1BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.m */,
83 | );
84 | name = Classes;
85 | path = ../Classes;
86 | sourceTree = "";
87 | };
88 | /* End PBXGroup section */
89 |
90 | /* Begin PBXHeadersBuildPhase section */
91 | E19608CA1BAD53AF00BDCBBE /* Headers */ = {
92 | isa = PBXHeadersBuildPhase;
93 | buildActionMask = 2147483647;
94 | files = (
95 | E19608E01BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.h in Headers */,
96 | E19608D11BAD53AF00BDCBBE /* FDTemplateLayoutCell.h in Headers */,
97 | 485022171C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.h in Headers */,
98 | 485022151C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.h in Headers */,
99 | 485022131C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.h in Headers */,
100 | );
101 | runOnlyForDeploymentPostprocessing = 0;
102 | };
103 | /* End PBXHeadersBuildPhase section */
104 |
105 | /* Begin PBXNativeTarget section */
106 | E19608CC1BAD53AF00BDCBBE /* FDTemplateLayoutCell */ = {
107 | isa = PBXNativeTarget;
108 | buildConfigurationList = E19608D51BAD53AF00BDCBBE /* Build configuration list for PBXNativeTarget "FDTemplateLayoutCell" */;
109 | buildPhases = (
110 | E19608C81BAD53AF00BDCBBE /* Sources */,
111 | E19608C91BAD53AF00BDCBBE /* Frameworks */,
112 | E19608CA1BAD53AF00BDCBBE /* Headers */,
113 | E19608CB1BAD53AF00BDCBBE /* Resources */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = FDTemplateLayoutCell;
120 | productName = FDTemplateLayoutCell;
121 | productReference = E19608CD1BAD53AF00BDCBBE /* FDTemplateLayoutCell.framework */;
122 | productType = "com.apple.product-type.framework";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | E19608C41BAD53AE00BDCBBE /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 0700;
131 | TargetAttributes = {
132 | E19608CC1BAD53AF00BDCBBE = {
133 | CreatedOnToolsVersion = 7.0;
134 | };
135 | };
136 | };
137 | buildConfigurationList = E19608C71BAD53AE00BDCBBE /* Build configuration list for PBXProject "FDTemplateLayoutCell" */;
138 | compatibilityVersion = "Xcode 3.2";
139 | developmentRegion = English;
140 | hasScannedForEncodings = 0;
141 | knownRegions = (
142 | en,
143 | );
144 | mainGroup = E19608C31BAD53AE00BDCBBE;
145 | productRefGroup = E19608CE1BAD53AF00BDCBBE /* Products */;
146 | projectDirPath = "";
147 | projectRoot = "";
148 | targets = (
149 | E19608CC1BAD53AF00BDCBBE /* FDTemplateLayoutCell */,
150 | );
151 | };
152 | /* End PBXProject section */
153 |
154 | /* Begin PBXResourcesBuildPhase section */
155 | E19608CB1BAD53AF00BDCBBE /* Resources */ = {
156 | isa = PBXResourcesBuildPhase;
157 | buildActionMask = 2147483647;
158 | files = (
159 | );
160 | runOnlyForDeploymentPostprocessing = 0;
161 | };
162 | /* End PBXResourcesBuildPhase section */
163 |
164 | /* Begin PBXSourcesBuildPhase section */
165 | E19608C81BAD53AF00BDCBBE /* Sources */ = {
166 | isa = PBXSourcesBuildPhase;
167 | buildActionMask = 2147483647;
168 | files = (
169 | 485022161C3A86EC00BD389E /* UITableView+FDKeyedHeightCache.m in Sources */,
170 | 485022181C3A86EC00BD389E /* UITableView+FDTemplateLayoutCellDebug.m in Sources */,
171 | E19608E11BAD54EB00BDCBBE /* UITableView+FDTemplateLayoutCell.m in Sources */,
172 | 485022141C3A86EC00BD389E /* UITableView+FDIndexPathHeightCache.m in Sources */,
173 | );
174 | runOnlyForDeploymentPostprocessing = 0;
175 | };
176 | /* End PBXSourcesBuildPhase section */
177 |
178 | /* Begin XCBuildConfiguration section */
179 | E19608D31BAD53AF00BDCBBE /* Debug */ = {
180 | isa = XCBuildConfiguration;
181 | buildSettings = {
182 | ALWAYS_SEARCH_USER_PATHS = NO;
183 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
184 | CLANG_CXX_LIBRARY = "libc++";
185 | CLANG_ENABLE_MODULES = YES;
186 | CLANG_ENABLE_OBJC_ARC = YES;
187 | CLANG_WARN_BOOL_CONVERSION = YES;
188 | CLANG_WARN_CONSTANT_CONVERSION = YES;
189 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
190 | CLANG_WARN_EMPTY_BODY = YES;
191 | CLANG_WARN_ENUM_CONVERSION = YES;
192 | CLANG_WARN_INT_CONVERSION = YES;
193 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
194 | CLANG_WARN_UNREACHABLE_CODE = YES;
195 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
196 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
197 | COPY_PHASE_STRIP = NO;
198 | CURRENT_PROJECT_VERSION = 1;
199 | DEBUG_INFORMATION_FORMAT = dwarf;
200 | ENABLE_STRICT_OBJC_MSGSEND = YES;
201 | ENABLE_TESTABILITY = YES;
202 | GCC_C_LANGUAGE_STANDARD = gnu99;
203 | GCC_DYNAMIC_NO_PIC = NO;
204 | GCC_NO_COMMON_BLOCKS = YES;
205 | GCC_OPTIMIZATION_LEVEL = 0;
206 | GCC_PREPROCESSOR_DEFINITIONS = (
207 | "DEBUG=1",
208 | "$(inherited)",
209 | );
210 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
211 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
212 | GCC_WARN_UNDECLARED_SELECTOR = YES;
213 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
214 | GCC_WARN_UNUSED_FUNCTION = YES;
215 | GCC_WARN_UNUSED_VARIABLE = YES;
216 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
217 | MTL_ENABLE_DEBUG_INFO = YES;
218 | ONLY_ACTIVE_ARCH = YES;
219 | SDKROOT = iphoneos;
220 | TARGETED_DEVICE_FAMILY = "1,2";
221 | VERSIONING_SYSTEM = "apple-generic";
222 | VERSION_INFO_PREFIX = "";
223 | };
224 | name = Debug;
225 | };
226 | E19608D41BAD53AF00BDCBBE /* Release */ = {
227 | isa = XCBuildConfiguration;
228 | buildSettings = {
229 | ALWAYS_SEARCH_USER_PATHS = NO;
230 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
231 | CLANG_CXX_LIBRARY = "libc++";
232 | CLANG_ENABLE_MODULES = YES;
233 | CLANG_ENABLE_OBJC_ARC = YES;
234 | CLANG_WARN_BOOL_CONVERSION = YES;
235 | CLANG_WARN_CONSTANT_CONVERSION = YES;
236 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
237 | CLANG_WARN_EMPTY_BODY = YES;
238 | CLANG_WARN_ENUM_CONVERSION = YES;
239 | CLANG_WARN_INT_CONVERSION = YES;
240 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
241 | CLANG_WARN_UNREACHABLE_CODE = YES;
242 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
243 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
244 | COPY_PHASE_STRIP = NO;
245 | CURRENT_PROJECT_VERSION = 1;
246 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
247 | ENABLE_NS_ASSERTIONS = NO;
248 | ENABLE_STRICT_OBJC_MSGSEND = YES;
249 | GCC_C_LANGUAGE_STANDARD = gnu99;
250 | GCC_NO_COMMON_BLOCKS = YES;
251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
253 | GCC_WARN_UNDECLARED_SELECTOR = YES;
254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
255 | GCC_WARN_UNUSED_FUNCTION = YES;
256 | GCC_WARN_UNUSED_VARIABLE = YES;
257 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
258 | MTL_ENABLE_DEBUG_INFO = NO;
259 | SDKROOT = iphoneos;
260 | TARGETED_DEVICE_FAMILY = "1,2";
261 | VALIDATE_PRODUCT = YES;
262 | VERSIONING_SYSTEM = "apple-generic";
263 | VERSION_INFO_PREFIX = "";
264 | };
265 | name = Release;
266 | };
267 | E19608D61BAD53AF00BDCBBE /* Debug */ = {
268 | isa = XCBuildConfiguration;
269 | buildSettings = {
270 | DEFINES_MODULE = YES;
271 | DYLIB_COMPATIBILITY_VERSION = 1;
272 | DYLIB_CURRENT_VERSION = 1;
273 | DYLIB_INSTALL_NAME_BASE = "@rpath";
274 | INFOPLIST_FILE = FDTemplateLayoutCell/Info.plist;
275 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
276 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
277 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
278 | PRODUCT_BUNDLE_IDENTIFIER = com.forkingdog.templatelayoutcell.FDTemplateLayoutCell;
279 | PRODUCT_NAME = "$(TARGET_NAME)";
280 | SKIP_INSTALL = YES;
281 | };
282 | name = Debug;
283 | };
284 | E19608D71BAD53AF00BDCBBE /* Release */ = {
285 | isa = XCBuildConfiguration;
286 | buildSettings = {
287 | DEFINES_MODULE = YES;
288 | DYLIB_COMPATIBILITY_VERSION = 1;
289 | DYLIB_CURRENT_VERSION = 1;
290 | DYLIB_INSTALL_NAME_BASE = "@rpath";
291 | INFOPLIST_FILE = FDTemplateLayoutCell/Info.plist;
292 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
293 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
294 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
295 | PRODUCT_BUNDLE_IDENTIFIER = com.forkingdog.templatelayoutcell.FDTemplateLayoutCell;
296 | PRODUCT_NAME = "$(TARGET_NAME)";
297 | SKIP_INSTALL = YES;
298 | };
299 | name = Release;
300 | };
301 | /* End XCBuildConfiguration section */
302 |
303 | /* Begin XCConfigurationList section */
304 | E19608C71BAD53AE00BDCBBE /* Build configuration list for PBXProject "FDTemplateLayoutCell" */ = {
305 | isa = XCConfigurationList;
306 | buildConfigurations = (
307 | E19608D31BAD53AF00BDCBBE /* Debug */,
308 | E19608D41BAD53AF00BDCBBE /* Release */,
309 | );
310 | defaultConfigurationIsVisible = 0;
311 | defaultConfigurationName = Release;
312 | };
313 | E19608D51BAD53AF00BDCBBE /* Build configuration list for PBXNativeTarget "FDTemplateLayoutCell" */ = {
314 | isa = XCConfigurationList;
315 | buildConfigurations = (
316 | E19608D61BAD53AF00BDCBBE /* Debug */,
317 | E19608D71BAD53AF00BDCBBE /* Release */,
318 | );
319 | defaultConfigurationIsVisible = 0;
320 | defaultConfigurationName = Release;
321 | };
322 | /* End XCConfigurationList section */
323 | };
324 | rootObject = E19608C41BAD53AE00BDCBBE /* Project object */;
325 | }
326 |
--------------------------------------------------------------------------------
/Demo/Demo/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "feed": [
3 | {
4 | "title": "Hello world",
5 | "content": "This is forkingdog team. Here's our logo?\nGithub: \"forkingdog\"",
6 | "username": "forkingdog",
7 | "time": "2015.04.10",
8 | "imageName": "forkingdog"
9 | },
10 | {
11 | "title": "Team member - sunnyxx",
12 | "content": "Working at Baidu, Zhidao iOS team, weibo: @我就叫Sunny怎么了",
13 | "username": "sunnyxx",
14 | "time": "2015.04.11",
15 | "imageName": "sunnyxx"
16 | },
17 | {
18 | "title": "Team member - SinoJerk",
19 | "content": "Zhidao iOS team, Daifu Tang (aka 彪哥)",
20 | "username": "sinojerk",
21 | "time": "2015.04.15",
22 | "imageName": "sinojerk"
23 | },
24 | {
25 | "title": "Team member - Phil",
26 | "content": "Zhidao iOS team, Jiaqi Guo, Github: philcn",
27 | "username": "phil",
28 | "time": "2015.04.15",
29 | "imageName": "phil"
30 | },
31 | {
32 | "title": "William Shakespeare",
33 | "content": "Good name in man and woman, dear my lord, is the immediate jewel of their souls: Who steals my purse steals trash; ’tis something, nothing. (Othello 3.3) ",
34 | "username": "sunnyxx",
35 | "time": "2015.04.12",
36 | "imageName": "breaddoge"
37 | },
38 | {
39 | "title": "William Shakespeare",
40 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
41 | "username": "sunnyxx",
42 | "time": "2015.04.16",
43 | "imageName": ""
44 | },
45 | {
46 | "title": "Sark's bad guy (gay)",
47 | "content": "",
48 | "username": "sunnyxx",
49 | "time": "2015.04.16",
50 | "imageName": "sark"
51 | },
52 | {
53 | "title": "",
54 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
55 | "username": "sunnyxx",
56 | "time": "2015.04.17",
57 | "imageName": ""
58 | },
59 | {
60 | "title": "William Shakespeare",
61 | "content": "Good name in man and woman, dear my lord, is the immediate jewel of their souls: Who steals my purse steals trash; ’tis something, nothing. (Othello 3.3) ",
62 | "username": "sunnyxx",
63 | "time": "2015.04.12",
64 | "imageName": "breaddoge"
65 | },
66 | {
67 | "title": "William Shakespeare",
68 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
69 | "username": "sunnyxx",
70 | "time": "2015.04.16",
71 | "imageName": ""
72 | },
73 | {
74 | "title": "Sark's bad guy (gay)",
75 | "content": "",
76 | "username": "sunnyxx",
77 | "time": "2015.04.16",
78 | "imageName": "sark"
79 | },
80 | {
81 | "title": "",
82 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
83 | "username": "sunnyxx",
84 | "time": "2015.04.17",
85 | "imageName": ""
86 | },
87 | {
88 | "title": "William Shakespeare",
89 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
90 | "username": "sunnyxx",
91 | "time": "2015.04.16",
92 | "imageName": ""
93 | },
94 | {
95 | "title": "Sark's bad guy (gay)",
96 | "content": "",
97 | "username": "sunnyxx",
98 | "time": "2015.04.16",
99 | "imageName": "sark"
100 | },
101 | {
102 | "title": "",
103 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
104 | "username": "sunnyxx",
105 | "time": "2015.04.17",
106 | "imageName": ""
107 | },
108 | {
109 | "title": "William Shakespeare",
110 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
111 | "username": "sunnyxx",
112 | "time": "2015.04.16",
113 | "imageName": ""
114 | },
115 | {
116 | "title": "Sark's bad guy (gay)",
117 | "content": "",
118 | "username": "sunnyxx",
119 | "time": "2015.04.16",
120 | "imageName": "sark"
121 | },
122 | {
123 | "title": "",
124 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
125 | "username": "sunnyxx",
126 | "time": "2015.04.17",
127 | "imageName": ""
128 | },
129 | {
130 | "title": "Hello world",
131 | "content": "This is forkingdog team. Here's our logo?\nGithub: \"forkingdog\"",
132 | "username": "forkingdog",
133 | "time": "2015.04.10",
134 | "imageName": "forkingdog"
135 | },
136 | {
137 | "title": "Team member - sunnyxx",
138 | "content": "Working at Baidu, Zhidao iOS team, weibo: @我就叫Sunny怎么了",
139 | "username": "sunnyxx",
140 | "time": "2015.04.11",
141 | "imageName": "sunnyxx"
142 | },
143 | {
144 | "title": "Team member - SinoJerk",
145 | "content": "Zhidao iOS team, Daifu Tang (aka 彪哥)",
146 | "username": "sinojerk",
147 | "time": "2015.04.15",
148 | "imageName": "sinojerk"
149 | },
150 | {
151 | "title": "Team member - Phil",
152 | "content": "Zhidao iOS team, Jiaqi Guo, Github: philcn",
153 | "username": "phil",
154 | "time": "2015.04.15",
155 | "imageName": "phil"
156 | },
157 | {
158 | "title": "William Shakespeare",
159 | "content": "Good name in man and woman, dear my lord, is the immediate jewel of their souls: Who steals my purse steals trash; ’tis something, nothing. (Othello 3.3) ",
160 | "username": "sunnyxx",
161 | "time": "2015.04.12",
162 | "imageName": "breaddoge"
163 | },
164 | {
165 | "title": "William Shakespeare",
166 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
167 | "username": "sunnyxx",
168 | "time": "2015.04.16",
169 | "imageName": ""
170 | },
171 | {
172 | "title": "Sark's bad guy (gay)",
173 | "content": "",
174 | "username": "sunnyxx",
175 | "time": "2015.04.16",
176 | "imageName": "sark"
177 | },
178 | {
179 | "title": "",
180 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
181 | "username": "sunnyxx",
182 | "time": "2015.04.17",
183 | "imageName": ""
184 | },
185 | {
186 | "title": "William Shakespeare",
187 | "content": "Good name in man and woman, dear my lord, is the immediate jewel of their souls: Who steals my purse steals trash; ’tis something, nothing. (Othello 3.3) ",
188 | "username": "sunnyxx",
189 | "time": "2015.04.12",
190 | "imageName": "breaddoge"
191 | },
192 | {
193 | "title": "William Shakespeare",
194 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
195 | "username": "sunnyxx",
196 | "time": "2015.04.16",
197 | "imageName": ""
198 | },
199 | {
200 | "title": "Sark's bad guy (gay)",
201 | "content": "",
202 | "username": "sunnyxx",
203 | "time": "2015.04.16",
204 | "imageName": "sark"
205 | },
206 | {
207 | "title": "",
208 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
209 | "username": "sunnyxx",
210 | "time": "2015.04.17",
211 | "imageName": ""
212 | },
213 | {
214 | "title": "William Shakespeare",
215 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
216 | "username": "sunnyxx",
217 | "time": "2015.04.16",
218 | "imageName": ""
219 | },
220 | {
221 | "title": "Sark's bad guy (gay)",
222 | "content": "",
223 | "username": "sunnyxx",
224 | "time": "2015.04.16",
225 | "imageName": "sark"
226 | },
227 | {
228 | "title": "",
229 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
230 | "username": "sunnyxx",
231 | "time": "2015.04.17",
232 | "imageName": ""
233 | },
234 | {
235 | "title": "William Shakespeare",
236 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
237 | "username": "sunnyxx",
238 | "time": "2015.04.16",
239 | "imageName": ""
240 | },
241 | {
242 | "title": "Sark's bad guy (gay)",
243 | "content": "",
244 | "username": "sunnyxx",
245 | "time": "2015.04.16",
246 | "imageName": "sark"
247 | },
248 | {
249 | "title": "",
250 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
251 | "username": "sunnyxx",
252 | "time": "2015.04.17",
253 | "imageName": ""
254 | },{
255 | "title": "Hello world",
256 | "content": "This is forkingdog team. Here's our logo?\nGithub: \"forkingdog\"",
257 | "username": "forkingdog",
258 | "time": "2015.04.10",
259 | "imageName": "forkingdog"
260 | },
261 | {
262 | "title": "Team member - sunnyxx",
263 | "content": "Working at Baidu, Zhidao iOS team, weibo: @我就叫Sunny怎么了",
264 | "username": "sunnyxx",
265 | "time": "2015.04.11",
266 | "imageName": "sunnyxx"
267 | },
268 | {
269 | "title": "Team member - SinoJerk",
270 | "content": "Zhidao iOS team, Daifu Tang (aka 彪哥)",
271 | "username": "sinojerk",
272 | "time": "2015.04.15",
273 | "imageName": "sinojerk"
274 | },
275 | {
276 | "title": "Team member - Phil",
277 | "content": "Zhidao iOS team, Jiaqi Guo, Github: philcn",
278 | "username": "phil",
279 | "time": "2015.04.15",
280 | "imageName": "phil"
281 | },
282 | {
283 | "title": "William Shakespeare",
284 | "content": "Good name in man and woman, dear my lord, is the immediate jewel of their souls: Who steals my purse steals trash; ’tis something, nothing. (Othello 3.3) ",
285 | "username": "sunnyxx",
286 | "time": "2015.04.12",
287 | "imageName": "breaddoge"
288 | },
289 | {
290 | "title": "William Shakespeare",
291 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
292 | "username": "sunnyxx",
293 | "time": "2015.04.16",
294 | "imageName": ""
295 | },
296 | {
297 | "title": "Sark's bad guy (gay)",
298 | "content": "",
299 | "username": "sunnyxx",
300 | "time": "2015.04.16",
301 | "imageName": "sark"
302 | },
303 | {
304 | "title": "",
305 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
306 | "username": "sunnyxx",
307 | "time": "2015.04.17",
308 | "imageName": ""
309 | },
310 | {
311 | "title": "William Shakespeare",
312 | "content": "Good name in man and woman, dear my lord, is the immediate jewel of their souls: Who steals my purse steals trash; ’tis something, nothing. (Othello 3.3) ",
313 | "username": "sunnyxx",
314 | "time": "2015.04.12",
315 | "imageName": "breaddoge"
316 | },
317 | {
318 | "title": "William Shakespeare",
319 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
320 | "username": "sunnyxx",
321 | "time": "2015.04.16",
322 | "imageName": ""
323 | },
324 | {
325 | "title": "Sark's bad guy (gay)",
326 | "content": "",
327 | "username": "sunnyxx",
328 | "time": "2015.04.16",
329 | "imageName": "sark"
330 | },
331 | {
332 | "title": "",
333 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
334 | "username": "sunnyxx",
335 | "time": "2015.04.17",
336 | "imageName": ""
337 | },
338 | {
339 | "title": "William Shakespeare",
340 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
341 | "username": "sunnyxx",
342 | "time": "2015.04.16",
343 | "imageName": ""
344 | },
345 | {
346 | "title": "Sark's bad guy (gay)",
347 | "content": "",
348 | "username": "sunnyxx",
349 | "time": "2015.04.16",
350 | "imageName": "sark"
351 | },
352 | {
353 | "title": "",
354 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
355 | "username": "sunnyxx",
356 | "time": "2015.04.17",
357 | "imageName": ""
358 | },
359 | {
360 | "title": "William Shakespeare",
361 | "content": "To be, or not to be —that is the question, Whether'tis nobler in the mind to suffer. The slings and arrows of outrageous fortune Or to take arms against a sea of troubles, And by opposing end them. To die —to sleep",
362 | "username": "sunnyxx",
363 | "time": "2015.04.16",
364 | "imageName": ""
365 | },
366 | {
367 | "title": "Sark's bad guy (gay)",
368 | "content": "",
369 | "username": "sunnyxx",
370 | "time": "2015.04.16",
371 | "imageName": "sark"
372 | },
373 | {
374 | "title": "",
375 | "content": "Things base and vile, holding no quantity, love can transpose to from and dignity: love looks not with the eyes, but with mind. (A Midsummer Night’s Dream 1.1)",
376 | "username": "sunnyxx",
377 | "time": "2015.04.17",
378 | "imageName": ""
379 | }
380 | ]
381 | }
382 |
--------------------------------------------------------------------------------
/Demo/Demo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 485DB89B1BAFFF8900CEAE33 /* UITableView+FDKeyedHeightCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 485DB89A1BAFFF8900CEAE33 /* UITableView+FDKeyedHeightCache.m */; settings = {ASSET_TAGS = (); }; };
11 | 485DB89E1BB0004300CEAE33 /* UITableView+FDIndexPathHeightCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 485DB89D1BB0004300CEAE33 /* UITableView+FDIndexPathHeightCache.m */; settings = {ASSET_TAGS = (); }; };
12 | 488EECB71ADFEDC6004EAA71 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 488EECB61ADFEDC6004EAA71 /* main.m */; };
13 | 488EECBA1ADFEDC6004EAA71 /* FDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 488EECB91ADFEDC6004EAA71 /* FDAppDelegate.m */; };
14 | 488EECC01ADFEDC6004EAA71 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 488EECBE1ADFEDC6004EAA71 /* Main.storyboard */; };
15 | 488EECC21ADFEDC6004EAA71 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 488EECC11ADFEDC6004EAA71 /* Images.xcassets */; };
16 | 488EECC51ADFEDC6004EAA71 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 488EECC31ADFEDC6004EAA71 /* LaunchScreen.xib */; };
17 | 488EECE01ADFF7A5004EAA71 /* FDFeedViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 488EECDF1ADFF7A5004EAA71 /* FDFeedViewController.m */; };
18 | 488EECE31ADFF884004EAA71 /* FDFeedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = 488EECE21ADFF884004EAA71 /* FDFeedEntity.m */; };
19 | 48954A261B5102E200EFD15D /* UITableView+FDTemplateLayoutCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 48954A1F1B5102E200EFD15D /* UITableView+FDTemplateLayoutCell.m */; };
20 | 48954A271B5102E200EFD15D /* UITableView+FDTemplateLayoutCellDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = 48954A211B5102E200EFD15D /* UITableView+FDTemplateLayoutCellDebug.m */; };
21 | 4897E5DD1ADFFBBD00E87B5F /* data.json in Resources */ = {isa = PBXBuildFile; fileRef = 4897E5DC1ADFFBBD00E87B5F /* data.json */; };
22 | 4897E5E01AE090B900E87B5F /* FDFeedCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4897E5DF1AE090B900E87B5F /* FDFeedCell.m */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXFileReference section */
26 | 485DB8991BAFFF8900CEAE33 /* UITableView+FDKeyedHeightCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDKeyedHeightCache.h"; sourceTree = ""; };
27 | 485DB89A1BAFFF8900CEAE33 /* UITableView+FDKeyedHeightCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDKeyedHeightCache.m"; sourceTree = ""; };
28 | 485DB89C1BB0004300CEAE33 /* UITableView+FDIndexPathHeightCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDIndexPathHeightCache.h"; sourceTree = ""; };
29 | 485DB89D1BB0004300CEAE33 /* UITableView+FDIndexPathHeightCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDIndexPathHeightCache.m"; sourceTree = ""; };
30 | 488EECB11ADFEDC6004EAA71 /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; };
31 | 488EECB51ADFEDC6004EAA71 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | 488EECB61ADFEDC6004EAA71 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
33 | 488EECB81ADFEDC6004EAA71 /* FDAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FDAppDelegate.h; sourceTree = ""; };
34 | 488EECB91ADFEDC6004EAA71 /* FDAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FDAppDelegate.m; sourceTree = ""; };
35 | 488EECBF1ADFEDC6004EAA71 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
36 | 488EECC11ADFEDC6004EAA71 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
37 | 488EECC41ADFEDC6004EAA71 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
38 | 488EECDE1ADFF7A5004EAA71 /* FDFeedViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FDFeedViewController.h; sourceTree = ""; };
39 | 488EECDF1ADFF7A5004EAA71 /* FDFeedViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FDFeedViewController.m; sourceTree = ""; };
40 | 488EECE11ADFF884004EAA71 /* FDFeedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FDFeedEntity.h; sourceTree = ""; };
41 | 488EECE21ADFF884004EAA71 /* FDFeedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FDFeedEntity.m; sourceTree = ""; };
42 | 48954A1E1B5102E200EFD15D /* UITableView+FDTemplateLayoutCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDTemplateLayoutCell.h"; sourceTree = ""; };
43 | 48954A1F1B5102E200EFD15D /* UITableView+FDTemplateLayoutCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDTemplateLayoutCell.m"; sourceTree = ""; };
44 | 48954A201B5102E200EFD15D /* UITableView+FDTemplateLayoutCellDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UITableView+FDTemplateLayoutCellDebug.h"; sourceTree = ""; };
45 | 48954A211B5102E200EFD15D /* UITableView+FDTemplateLayoutCellDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UITableView+FDTemplateLayoutCellDebug.m"; sourceTree = ""; };
46 | 4897E5DC1ADFFBBD00E87B5F /* data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = data.json; sourceTree = ""; };
47 | 4897E5DE1AE090B900E87B5F /* FDFeedCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FDFeedCell.h; sourceTree = ""; };
48 | 4897E5DF1AE090B900E87B5F /* FDFeedCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FDFeedCell.m; sourceTree = ""; };
49 | /* End PBXFileReference section */
50 |
51 | /* Begin PBXFrameworksBuildPhase section */
52 | 488EECAE1ADFEDC6004EAA71 /* Frameworks */ = {
53 | isa = PBXFrameworksBuildPhase;
54 | buildActionMask = 2147483647;
55 | files = (
56 | );
57 | runOnlyForDeploymentPostprocessing = 0;
58 | };
59 | /* End PBXFrameworksBuildPhase section */
60 |
61 | /* Begin PBXGroup section */
62 | 488EECA81ADFEDC6004EAA71 = {
63 | isa = PBXGroup;
64 | children = (
65 | 488EECB31ADFEDC6004EAA71 /* Demo */,
66 | 488EECB21ADFEDC6004EAA71 /* Products */,
67 | );
68 | sourceTree = "";
69 | };
70 | 488EECB21ADFEDC6004EAA71 /* Products */ = {
71 | isa = PBXGroup;
72 | children = (
73 | 488EECB11ADFEDC6004EAA71 /* Demo.app */,
74 | );
75 | name = Products;
76 | sourceTree = "";
77 | };
78 | 488EECB31ADFEDC6004EAA71 /* Demo */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 48954A191B5102E200EFD15D /* Classes */,
82 | 488EECEA1ADFF905004EAA71 /* Feed */,
83 | 488EECC11ADFEDC6004EAA71 /* Images.xcassets */,
84 | 488EECC31ADFEDC6004EAA71 /* LaunchScreen.xib */,
85 | 488EECB41ADFEDC6004EAA71 /* Supporting Files */,
86 | );
87 | path = Demo;
88 | sourceTree = "";
89 | };
90 | 488EECB41ADFEDC6004EAA71 /* Supporting Files */ = {
91 | isa = PBXGroup;
92 | children = (
93 | 488EECB51ADFEDC6004EAA71 /* Info.plist */,
94 | 488EECB61ADFEDC6004EAA71 /* main.m */,
95 | );
96 | name = "Supporting Files";
97 | sourceTree = "";
98 | };
99 | 488EECEA1ADFF905004EAA71 /* Feed */ = {
100 | isa = PBXGroup;
101 | children = (
102 | 488EECE11ADFF884004EAA71 /* FDFeedEntity.h */,
103 | 488EECE21ADFF884004EAA71 /* FDFeedEntity.m */,
104 | 488EECB81ADFEDC6004EAA71 /* FDAppDelegate.h */,
105 | 488EECB91ADFEDC6004EAA71 /* FDAppDelegate.m */,
106 | 488EECDE1ADFF7A5004EAA71 /* FDFeedViewController.h */,
107 | 488EECDF1ADFF7A5004EAA71 /* FDFeedViewController.m */,
108 | 4897E5DE1AE090B900E87B5F /* FDFeedCell.h */,
109 | 4897E5DF1AE090B900E87B5F /* FDFeedCell.m */,
110 | 488EECBE1ADFEDC6004EAA71 /* Main.storyboard */,
111 | 4897E5DC1ADFFBBD00E87B5F /* data.json */,
112 | );
113 | name = Feed;
114 | sourceTree = "";
115 | };
116 | 48954A191B5102E200EFD15D /* Classes */ = {
117 | isa = PBXGroup;
118 | children = (
119 | 48954A1E1B5102E200EFD15D /* UITableView+FDTemplateLayoutCell.h */,
120 | 48954A1F1B5102E200EFD15D /* UITableView+FDTemplateLayoutCell.m */,
121 | 485DB8991BAFFF8900CEAE33 /* UITableView+FDKeyedHeightCache.h */,
122 | 485DB89A1BAFFF8900CEAE33 /* UITableView+FDKeyedHeightCache.m */,
123 | 485DB89C1BB0004300CEAE33 /* UITableView+FDIndexPathHeightCache.h */,
124 | 485DB89D1BB0004300CEAE33 /* UITableView+FDIndexPathHeightCache.m */,
125 | 48954A201B5102E200EFD15D /* UITableView+FDTemplateLayoutCellDebug.h */,
126 | 48954A211B5102E200EFD15D /* UITableView+FDTemplateLayoutCellDebug.m */,
127 | );
128 | name = Classes;
129 | path = ../../Classes;
130 | sourceTree = "";
131 | };
132 | /* End PBXGroup section */
133 |
134 | /* Begin PBXNativeTarget section */
135 | 488EECB01ADFEDC6004EAA71 /* Demo */ = {
136 | isa = PBXNativeTarget;
137 | buildConfigurationList = 488EECD41ADFEDC6004EAA71 /* Build configuration list for PBXNativeTarget "Demo" */;
138 | buildPhases = (
139 | 488EECAD1ADFEDC6004EAA71 /* Sources */,
140 | 488EECAE1ADFEDC6004EAA71 /* Frameworks */,
141 | 488EECAF1ADFEDC6004EAA71 /* Resources */,
142 | );
143 | buildRules = (
144 | );
145 | dependencies = (
146 | );
147 | name = Demo;
148 | productName = Demo;
149 | productReference = 488EECB11ADFEDC6004EAA71 /* Demo.app */;
150 | productType = "com.apple.product-type.application";
151 | };
152 | /* End PBXNativeTarget section */
153 |
154 | /* Begin PBXProject section */
155 | 488EECA91ADFEDC6004EAA71 /* Project object */ = {
156 | isa = PBXProject;
157 | attributes = {
158 | LastUpgradeCheck = 0630;
159 | ORGANIZATIONNAME = forkingdog;
160 | TargetAttributes = {
161 | 488EECB01ADFEDC6004EAA71 = {
162 | CreatedOnToolsVersion = 6.3;
163 | };
164 | };
165 | };
166 | buildConfigurationList = 488EECAC1ADFEDC6004EAA71 /* Build configuration list for PBXProject "Demo" */;
167 | compatibilityVersion = "Xcode 3.2";
168 | developmentRegion = English;
169 | hasScannedForEncodings = 0;
170 | knownRegions = (
171 | en,
172 | Base,
173 | );
174 | mainGroup = 488EECA81ADFEDC6004EAA71;
175 | productRefGroup = 488EECB21ADFEDC6004EAA71 /* Products */;
176 | projectDirPath = "";
177 | projectRoot = "";
178 | targets = (
179 | 488EECB01ADFEDC6004EAA71 /* Demo */,
180 | );
181 | };
182 | /* End PBXProject section */
183 |
184 | /* Begin PBXResourcesBuildPhase section */
185 | 488EECAF1ADFEDC6004EAA71 /* Resources */ = {
186 | isa = PBXResourcesBuildPhase;
187 | buildActionMask = 2147483647;
188 | files = (
189 | 488EECC01ADFEDC6004EAA71 /* Main.storyboard in Resources */,
190 | 488EECC51ADFEDC6004EAA71 /* LaunchScreen.xib in Resources */,
191 | 488EECC21ADFEDC6004EAA71 /* Images.xcassets in Resources */,
192 | 4897E5DD1ADFFBBD00E87B5F /* data.json in Resources */,
193 | );
194 | runOnlyForDeploymentPostprocessing = 0;
195 | };
196 | /* End PBXResourcesBuildPhase section */
197 |
198 | /* Begin PBXSourcesBuildPhase section */
199 | 488EECAD1ADFEDC6004EAA71 /* Sources */ = {
200 | isa = PBXSourcesBuildPhase;
201 | buildActionMask = 2147483647;
202 | files = (
203 | 488EECBA1ADFEDC6004EAA71 /* FDAppDelegate.m in Sources */,
204 | 48954A261B5102E200EFD15D /* UITableView+FDTemplateLayoutCell.m in Sources */,
205 | 48954A271B5102E200EFD15D /* UITableView+FDTemplateLayoutCellDebug.m in Sources */,
206 | 488EECE01ADFF7A5004EAA71 /* FDFeedViewController.m in Sources */,
207 | 4897E5E01AE090B900E87B5F /* FDFeedCell.m in Sources */,
208 | 488EECB71ADFEDC6004EAA71 /* main.m in Sources */,
209 | 485DB89B1BAFFF8900CEAE33 /* UITableView+FDKeyedHeightCache.m in Sources */,
210 | 485DB89E1BB0004300CEAE33 /* UITableView+FDIndexPathHeightCache.m in Sources */,
211 | 488EECE31ADFF884004EAA71 /* FDFeedEntity.m in Sources */,
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | };
215 | /* End PBXSourcesBuildPhase section */
216 |
217 | /* Begin PBXVariantGroup section */
218 | 488EECBE1ADFEDC6004EAA71 /* Main.storyboard */ = {
219 | isa = PBXVariantGroup;
220 | children = (
221 | 488EECBF1ADFEDC6004EAA71 /* Base */,
222 | );
223 | name = Main.storyboard;
224 | sourceTree = "";
225 | };
226 | 488EECC31ADFEDC6004EAA71 /* LaunchScreen.xib */ = {
227 | isa = PBXVariantGroup;
228 | children = (
229 | 488EECC41ADFEDC6004EAA71 /* Base */,
230 | );
231 | name = LaunchScreen.xib;
232 | sourceTree = "";
233 | };
234 | /* End PBXVariantGroup section */
235 |
236 | /* Begin XCBuildConfiguration section */
237 | 488EECD21ADFEDC6004EAA71 /* Debug */ = {
238 | isa = XCBuildConfiguration;
239 | buildSettings = {
240 | ALWAYS_SEARCH_USER_PATHS = NO;
241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
242 | CLANG_CXX_LIBRARY = "libc++";
243 | CLANG_ENABLE_MODULES = YES;
244 | CLANG_ENABLE_OBJC_ARC = YES;
245 | CLANG_WARN_BOOL_CONVERSION = YES;
246 | CLANG_WARN_CONSTANT_CONVERSION = YES;
247 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
248 | CLANG_WARN_EMPTY_BODY = YES;
249 | CLANG_WARN_ENUM_CONVERSION = YES;
250 | CLANG_WARN_INT_CONVERSION = YES;
251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
252 | CLANG_WARN_UNREACHABLE_CODE = YES;
253 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
254 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
255 | COPY_PHASE_STRIP = NO;
256 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
257 | ENABLE_STRICT_OBJC_MSGSEND = YES;
258 | GCC_C_LANGUAGE_STANDARD = gnu99;
259 | GCC_DYNAMIC_NO_PIC = NO;
260 | GCC_NO_COMMON_BLOCKS = YES;
261 | GCC_OPTIMIZATION_LEVEL = 0;
262 | GCC_PREPROCESSOR_DEFINITIONS = (
263 | "DEBUG=1",
264 | "$(inherited)",
265 | );
266 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
267 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
268 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
269 | GCC_WARN_UNDECLARED_SELECTOR = YES;
270 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
271 | GCC_WARN_UNUSED_FUNCTION = YES;
272 | GCC_WARN_UNUSED_VARIABLE = YES;
273 | IPHONEOS_DEPLOYMENT_TARGET = 6.0;
274 | MTL_ENABLE_DEBUG_INFO = YES;
275 | ONLY_ACTIVE_ARCH = YES;
276 | SDKROOT = iphoneos;
277 | };
278 | name = Debug;
279 | };
280 | 488EECD31ADFEDC6004EAA71 /* Release */ = {
281 | isa = XCBuildConfiguration;
282 | buildSettings = {
283 | ALWAYS_SEARCH_USER_PATHS = NO;
284 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
285 | CLANG_CXX_LIBRARY = "libc++";
286 | CLANG_ENABLE_MODULES = YES;
287 | CLANG_ENABLE_OBJC_ARC = YES;
288 | CLANG_WARN_BOOL_CONVERSION = YES;
289 | CLANG_WARN_CONSTANT_CONVERSION = YES;
290 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
291 | CLANG_WARN_EMPTY_BODY = YES;
292 | CLANG_WARN_ENUM_CONVERSION = YES;
293 | CLANG_WARN_INT_CONVERSION = YES;
294 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
295 | CLANG_WARN_UNREACHABLE_CODE = YES;
296 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
297 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
298 | COPY_PHASE_STRIP = NO;
299 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
300 | ENABLE_NS_ASSERTIONS = NO;
301 | ENABLE_STRICT_OBJC_MSGSEND = YES;
302 | GCC_C_LANGUAGE_STANDARD = gnu99;
303 | GCC_NO_COMMON_BLOCKS = YES;
304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
306 | GCC_WARN_UNDECLARED_SELECTOR = YES;
307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
308 | GCC_WARN_UNUSED_FUNCTION = YES;
309 | GCC_WARN_UNUSED_VARIABLE = YES;
310 | IPHONEOS_DEPLOYMENT_TARGET = 6.0;
311 | MTL_ENABLE_DEBUG_INFO = NO;
312 | SDKROOT = iphoneos;
313 | VALIDATE_PRODUCT = YES;
314 | };
315 | name = Release;
316 | };
317 | 488EECD51ADFEDC6004EAA71 /* Debug */ = {
318 | isa = XCBuildConfiguration;
319 | buildSettings = {
320 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
321 | INFOPLIST_FILE = Demo/Info.plist;
322 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
323 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | };
326 | name = Debug;
327 | };
328 | 488EECD61ADFEDC6004EAA71 /* Release */ = {
329 | isa = XCBuildConfiguration;
330 | buildSettings = {
331 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
332 | INFOPLIST_FILE = Demo/Info.plist;
333 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
334 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
335 | PRODUCT_NAME = "$(TARGET_NAME)";
336 | };
337 | name = Release;
338 | };
339 | /* End XCBuildConfiguration section */
340 |
341 | /* Begin XCConfigurationList section */
342 | 488EECAC1ADFEDC6004EAA71 /* Build configuration list for PBXProject "Demo" */ = {
343 | isa = XCConfigurationList;
344 | buildConfigurations = (
345 | 488EECD21ADFEDC6004EAA71 /* Debug */,
346 | 488EECD31ADFEDC6004EAA71 /* Release */,
347 | );
348 | defaultConfigurationIsVisible = 0;
349 | defaultConfigurationName = Release;
350 | };
351 | 488EECD41ADFEDC6004EAA71 /* Build configuration list for PBXNativeTarget "Demo" */ = {
352 | isa = XCConfigurationList;
353 | buildConfigurations = (
354 | 488EECD51ADFEDC6004EAA71 /* Debug */,
355 | 488EECD61ADFEDC6004EAA71 /* Release */,
356 | );
357 | defaultConfigurationIsVisible = 0;
358 | defaultConfigurationName = Release;
359 | };
360 | /* End XCConfigurationList section */
361 | };
362 | rootObject = 488EECA91ADFEDC6004EAA71 /* Project object */;
363 | }
364 |
--------------------------------------------------------------------------------