Repository: gnou/FakeZhihuDaily Branch: master Commit: 7f7661da18ef Files: 68 Total size: 169.3 KB Directory structure: gitextract_le9q9umy/ ├── .gitignore ├── FakeZhihuDaily/ │ ├── AppDelegate+MOC.h │ ├── AppDelegate+MOC.m │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj/ │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── ContentHeaderView.h │ ├── ContentHeaderView.m │ ├── ContentHeaderView.xib │ ├── ContentViewController.h │ ├── ContentViewController.m │ ├── Date+Create.h │ ├── Date+Create.m │ ├── Date.h │ ├── Date.m │ ├── FZDError.h │ ├── FakeZhihuDaily-Bridging-Header.h │ ├── FakeZhihuDaily.xcdatamodeld/ │ │ └── FakeZhihuDaily.xcdatamodel/ │ │ └── contents │ ├── Images.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── _placeholder.imageset/ │ │ │ └── Contents.json │ │ ├── contentPlaceHolder.imageset/ │ │ │ └── Contents.json │ │ ├── jellyfish.imageset/ │ │ │ └── Contents.json │ │ ├── placeholder.imageset/ │ │ │ └── Contents.json │ │ └── sideMenu.imageset/ │ │ └── Contents.json │ ├── Info.plist │ ├── Localizable.strings │ ├── MainStoriesViewController.h │ ├── MainStoriesViewController.m │ ├── NetworkClient.h │ ├── NetworkClient.m │ ├── NetworkManager.h │ ├── NetworkManager.m │ ├── SideBarTableViewController.h │ ├── SideBarTableViewController.m │ ├── StoriesList.swift │ ├── Story+Create.h │ ├── Story+Create.m │ ├── Story.h │ ├── Story.m │ ├── Theme+Create.h │ ├── Theme+Create.m │ ├── Theme.h │ ├── Theme.m │ ├── ThemeBodyViewController.h │ ├── ThemeBodyViewController.m │ ├── ThemeStoriesViewController.h │ ├── ThemeStoriesViewController.m │ ├── ThemeStory+Create.h │ ├── ThemeStory+Create.m │ ├── ThemeStory.h │ ├── ThemeStory.m │ ├── Title.h │ ├── Title.m │ ├── TitleCell.h │ ├── TitleCell.m │ └── main.m ├── FakeZhihuDaily.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ └── xcuserdata/ │ └── mc.xcuserdatad/ │ └── xcschemes/ │ ├── FakeZhihuDaily.xcscheme │ └── xcschememanagement.plist ├── FakeZhihuDaily.xcworkspace/ │ ├── contents.xcworkspacedata │ └── xcuserdata/ │ └── mc.xcuserdatad/ │ ├── WorkspaceSettings.xcsettings │ └── xcdebugger/ │ └── Breakpoints_v2.xcbkptlist ├── FakeZhihuDailyTests/ │ ├── FakeZhihuDailyTests.m │ └── Info.plist ├── Podfile └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.lock *.swp Pods/ ================================================ FILE: FakeZhihuDaily/AppDelegate+MOC.h ================================================ // // AppDelegate+MOC.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/6. // Copyright (c) 2014年 gnou. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate (MOC) - (void)saveContext:(NSManagedObjectContext *)managedObjectContext; - (NSManagedObjectContext *)createMainQueueManagedObjectContext; @end ================================================ FILE: FakeZhihuDaily/AppDelegate+MOC.m ================================================ // // AppDelegate+MOC.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/6. // Copyright (c) 2014年 gnou. All rights reserved. // #import "AppDelegate+MOC.h" @implementation AppDelegate (MOC) #pragma mark - Core Data - (void)saveContext:(NSManagedObjectContext *)managedObjectContext { NSError *error = nil; if (managedObjectContext != nil) { if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { // Replace this implementation with code to handle the error appropriately. // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } } } // Returns the managed object context for the application. // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. - (NSManagedObjectContext *)createMainQueueManagedObjectContext { NSManagedObjectContext *managedObjectContext = nil; NSPersistentStoreCoordinator *coordinator = [self createPersistentStoreCoordinator]; if (coordinator != nil) { managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [managedObjectContext setPersistentStoreCoordinator:coordinator]; } return managedObjectContext; } // Returns the managed object model for the application. // If the model doesn't already exist, it is created from the application's model. - (NSManagedObjectModel *)createManagedObjectModel { NSManagedObjectModel *managedObjectModel = nil; NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"FakeZhihuDaily" withExtension:@"momd"]; managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return managedObjectModel; } // Returns the persistent store coordinator for the application. // If the coordinator doesn't already exist, it is created and the application's store added to it. - (NSPersistentStoreCoordinator *)createPersistentStoreCoordinator { NSPersistentStoreCoordinator *persistentStoreCoordinator = nil; NSManagedObjectModel *managedObjectModel = [self createManagedObjectModel]; NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"FakeZhihuDaily.sqlite"]; NSError *error = nil; persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel]; if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { /* Replace this implementation with code to handle the error appropriately. abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. Typical reasons for an error here include: * The persistent store is not accessible; * The schema for the persistent store is incompatible with current managed object model. Check the error message to determine what the actual problem was. If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. If you encounter schema incompatibility errors during development, you can reduce their frequency by: * Simply deleting the existing store: [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] * Performing automatic lightweight migration by passing the following dictionary as the options parameter: @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. */ NSLog(@"Unresolved error %@, %@", error, [error userInfo]); abort(); } return persistentStoreCoordinator; } // Returns the URL to the application's Documents directory - (NSURL *)applicationDocumentsDirectory { return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; } @end ================================================ FILE: FakeZhihuDaily/AppDelegate.h ================================================ // // AppDelegate.h // FakeZhihuDaily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; - (UIColor *)tintColor; - (NSString *)dateStringOfToday; - (BOOL)isValidDateString:(NSString *)dateString; //- (void)fetchStoriesOfDate:(NSString *)dateString; @end ================================================ FILE: FakeZhihuDaily/AppDelegate.m ================================================ // // AppDelegate.m // FakeZhihuDaily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import "AppDelegate.h" #import "AppDelegate+MOC.h" #import "Story+Create.h" #import "Theme+Create.h" #import "NetworkClient.h" //@interface AppDelegate () //@property (nonatomic, strong) NSURLSession *downloadStorysSession; //@end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.managedObjectContext = [self createMainQueueManagedObjectContext]; [self initAppearence]; NetworkClient *networkClient = [[NetworkClient alloc] init]; [[networkClient fetchAndSaveLatestStoriesIntoManagedObjectContext:self.managedObjectContext] subscribeError:^(NSError *error) { NSLog(@"ERROR : %@", error); }]; [[networkClient fetchAndSaveThemesIntoManagedObjectContext:self.managedObjectContext] subscribeError:^(NSError *error) { NSLog(@"ERROR : %@", error); }]; return YES; } - (UIColor *)tintColor { return [UIColor colorWithRed:76/255.0f green:211/255.0f blue:235/255.0f alpha:1.0f]; } - (void)initAppearence { UIColor *myTintColor = [self tintColor]; [[UINavigationBar appearance] setBarStyle:UIBarStyleDefault]; [[UINavigationBar appearance] setBarTintColor:myTintColor]; } - (NSString *)dateStringOfToday { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyyMMdd"]; return [dateFormatter stringFromDate:[NSDate date]]; } - (BOOL)isValidDateString:(NSString *)dateString { return dateString.integerValue > 20130520 && dateString.integerValue <= [self dateStringOfToday].integerValue; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: FakeZhihuDaily/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: FakeZhihuDaily/Base.lproj/Main.storyboard ================================================ ================================================ FILE: FakeZhihuDaily/ContentHeaderView.h ================================================ // // ContentHeaderView.h // FakeZhihuDaily // // Created by CuiMingyu on 15/1/6. // Copyright (c) 2015年 gnou. All rights reserved. // #import @interface ContentHeaderView : UIView @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UILabel *imageSourceLabel; @property (weak, nonatomic) IBOutlet UILabel *titleLabel; @end ================================================ FILE: FakeZhihuDaily/ContentHeaderView.m ================================================ // // ContentHeaderView.m // FakeZhihuDaily // // Created by CuiMingyu on 15/1/6. // Copyright (c) 2015年 gnou. All rights reserved. // #import "ContentHeaderView.h" @implementation ContentHeaderView /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ //- (instancetype)initWithFrame:(CGRect)frame image:(UIImage *)image { // return [self initWithImage:image titleString:@"testTitle" imageSourceString:@"testImageSource" frame:frame]; //} // //- (instancetype)initWithImage:(UIImage *)image // titleString:(NSString *)titleString // imageSourceString:(NSString *)imageSourceString // frame:(CGRect)frame { // // self = [super initWithFrame:frame]; // if (self) { // self.imageView.image = image; // self.titleLabel.text = titleString; // self.imageSourceLabel.text = imageSourceString; // } // return self; //} @end ================================================ FILE: FakeZhihuDaily/ContentHeaderView.xib ================================================ ================================================ FILE: FakeZhihuDaily/ContentViewController.h ================================================ // // ContentViewController.h // FakeZhihuDaily // // Created by CuiMingyu on 15/1/6. // Copyright (c) 2015年 gnou. All rights reserved. // #import @interface ContentViewController : UIViewController @property (nonatomic, strong) NSNumber *id; - (NSString *)generateWebPageFromDictionary:(NSDictionary *)dictionary; @end ================================================ FILE: FakeZhihuDaily/ContentViewController.m ================================================ // // ContentViewController.m // FakeZhihuDaily // // Created by CuiMingyu on 15/1/6. // Copyright (c) 2015年 gnou. All rights reserved. // #import "ContentViewController.h" #import #import #import #import "ContentHeaderView.h" @interface ContentViewController () @property (weak, nonatomic) IBOutlet UIWebView *webView; @property (nonatomic, strong) NSURL *url; @property (nonatomic, strong) NSURLSession *session; //@property (nonatomic, strong) UIImageView *imageView; @property (nonatomic, strong) NSString *imageURLString; @property (nonatomic, strong) UIImage *headerImage; @property (nonatomic, strong) NSString *htmlString; @property (nonatomic, strong) NSString *titleString; @property (nonatomic, strong) NSString *imageSourceString; @end @implementation ContentViewController - (void)setId:(NSNumber *)id { _id = id; NSString *urlString = [NSString stringWithFormat:@"http://news-at.zhihu.com/api/3/news/%@", id.stringValue]; self.url = [NSURL URLWithString:urlString]; } - (NSURLSession *)session { if (!_session) { NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; _session = [NSURLSession sessionWithConfiguration:configuration]; } return _session; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self.navigationController.interactivePopGestureRecognizer setDelegate:nil]; self.webView.delegate = self; self.automaticallyAdjustsScrollViewInsets = NO; @weakify(self) [[[[[RACObserve(self, url) ignore:nil] flattenMap:^RACStream *(NSURL *url) { @strongify(self); return [self fetchBodyForURL:url]; }] flattenMap:^RACStream *(NSDictionary *dict) { self.htmlString = [self generateWebPageFromDictionary:dict]; self.titleString = dict[@"title"]; self.imageSourceString = dict[@"image_source"]; // Assume image exist NSString *imageURLString = dict[@"image"]; if (imageURLString) { return [self fetchImageForURLString:imageURLString]; } else { return nil; } }] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(UIImage *image) { @strongify(self) // Load html string [self.webView loadHTMLString:self.htmlString baseURL:nil]; if (image) { // init header view from nib NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"ContentHeaderView" owner:self options:nil]; ContentHeaderView *headerView = [nibArray firstObject]; // Setup header view CGRect headerFrame = CGRectMake(0, 0, self.webView.frame.size.width, 220); headerView.frame = headerFrame; headerView.imageView.image = image; headerView.titleLabel.text = self.titleString; headerView.imageSourceLabel.text = self.imageSourceString; [self.webView.scrollView addSubview:headerView]; } } error:^(NSError *error) { NSLog(@"ERROR: %@", error.localizedDescription); }]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (RACSignal *)fetchBodyForURL:(NSURL *)url { return [RACSignal createSignal:^RACDisposable *(id subscriber) { NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { [subscriber sendError:error]; } else { NSError *jsonError; NSDictionary *bodyDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&jsonError]; if (jsonError) { [subscriber sendError:jsonError]; } else { [subscriber sendNext:bodyDictionary]; } } }]; [dataTask resume]; return [RACDisposable disposableWithBlock:^{ [dataTask cancel]; }]; }]; } - (RACSignal *)fetchImageForURLString:(NSString *)imageURLString { return [RACSignal createSignal:^RACDisposable *(id subscriber) { NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:imageURLString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { [subscriber sendError:error]; } else { UIImage *newImage = [UIImage imageWithData:data]; [subscriber sendNext:newImage]; } }]; [dataTask resume]; return [RACDisposable disposableWithBlock:^{ [dataTask cancel]; }]; }]; } - (NSString *)generateWebPageFromDictionary:(NSDictionary *)dictionary { NSString *htmlBodyString = dictionary[@"body"]; NSString *cssURLString = dictionary[@"css"][0]; NSString *htmlString = [NSString stringWithFormat:@"%@", cssURLString, htmlBodyString]; return htmlString; } @end ================================================ FILE: FakeZhihuDaily/Date+Create.h ================================================ // // Date+Create.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/10. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Date.h" @interface Date (Create) + (Date *)dateWithDateString:(NSString *)dateString inManagedObjectContext:(NSManagedObjectContext *)context; @end ================================================ FILE: FakeZhihuDaily/Date+Create.m ================================================ // // Date+Create.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/10. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Date+Create.h" @implementation Date (Create) + (Date *)dateWithDateString:(NSString *)dateString inManagedObjectContext:(NSManagedObjectContext *)context { Date *date = nil; if ([dateString length]) { NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Date"]; request.predicate = [NSPredicate predicateWithFormat:@"dateString = %@", dateString]; NSError *error; NSArray *matchArray = [context executeFetchRequest:request error:&error]; if (!matchArray || error || [matchArray count] > 1) { // Handle Error NSLog(@"ERROR in %s", __FUNCTION__); } else if ([matchArray count]) { date = matchArray.firstObject; } else if (![matchArray count]){ date = [NSEntityDescription insertNewObjectForEntityForName:@"Date" inManagedObjectContext:context]; date.dateString = dateString; } } return date; } @end ================================================ FILE: FakeZhihuDaily/Date.h ================================================ // // Date.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/10. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @class Story; @interface Date : NSManagedObject @property (nonatomic, retain) NSString * dateString; @property (nonatomic, retain) NSSet *stories; @end @interface Date (CoreDataGeneratedAccessors) - (void)addStoriesObject:(Story *)value; - (void)removeStoriesObject:(Story *)value; - (void)addStories:(NSSet *)values; - (void)removeStories:(NSSet *)values; @end ================================================ FILE: FakeZhihuDaily/Date.m ================================================ // // Date.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/10. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Date.h" #import "Story.h" @implementation Date @dynamic dateString; @dynamic stories; @end ================================================ FILE: FakeZhihuDaily/FZDError.h ================================================ // // FZDError.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/18. // Copyright (c) 2014年 gnou. All rights reserved. // #ifndef FakeZhihuDaily_FZDError_h #define FakeZhihuDaily_FZDError_h #define FZDErrorDomain @"FakeZhihuDailyDomain" typedef enum : NSUInteger { FZDInvalidDateString, FZDNoMangedObjectContext, } FZDError; #endif ================================================ FILE: FakeZhihuDaily/FakeZhihuDaily-Bridging-Header.h ================================================ // // Use this file to import your target's public headers that you would like to expose to Swift. // ================================================ FILE: FakeZhihuDaily/FakeZhihuDaily.xcdatamodeld/FakeZhihuDaily.xcdatamodel/contents ================================================ ================================================ FILE: FakeZhihuDaily/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "size" : "29x29", "idiom" : "iphone", "filename" : "58-1.png", "scale" : "2x" }, { "size" : "29x29", "idiom" : "iphone", "filename" : "87.png", "scale" : "3x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "80.png", "scale" : "2x" }, { "size" : "40x40", "idiom" : "iphone", "filename" : "120.png", "scale" : "3x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "icon@2x.png", "scale" : "2x" }, { "size" : "60x60", "idiom" : "iphone", "filename" : "icon@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: FakeZhihuDaily/Images.xcassets/_placeholder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "placeholder.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "placeholder@2x.png" }, { "idiom" : "universal", "scale" : "3x", "filename" : "placeholder@3x.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: FakeZhihuDaily/Images.xcassets/contentPlaceHolder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "contentPlaceHolder.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "contentPlaceHolder@2x.png" }, { "idiom" : "universal", "scale" : "3x", "filename" : "contentPlaceHolder@3x.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: FakeZhihuDaily/Images.xcassets/jellyfish.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "jellyfish.jpg" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: FakeZhihuDaily/Images.xcassets/placeholder.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "placeholder.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "placeholder@2x.png" }, { "idiom" : "universal", "scale" : "3x", "filename" : "placeholder@3x.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: FakeZhihuDaily/Images.xcassets/sideMenu.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "scale" : "1x", "filename" : "sideMenu.png" }, { "idiom" : "universal", "scale" : "2x", "filename" : "sideMenu@2x.png" }, { "idiom" : "universal", "scale" : "3x", "filename" : "sideMenu@3x.png" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: FakeZhihuDaily/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleDisplayName 吱吱 CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier com.gnou.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UILaunchStoryboardName Main UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait ================================================ FILE: FakeZhihuDaily/Localizable.strings ================================================ /* Localizable.strings FakeZhihuDaily Created by CuiMingyu on 14/12/11. Copyright (c) 2014年 gnou. All rights reserved. */ ================================================ FILE: FakeZhihuDaily/MainStoriesViewController.h ================================================ // // StoryCDTVC.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/6. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @interface MainStoriesViewController : UIViewController @property (weak, nonatomic) IBOutlet UIBarButtonItem *sideBarButton; @end ================================================ FILE: FakeZhihuDaily/MainStoriesViewController.m ================================================ // // StoryCDTVC.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/6. // Copyright (c) 2014年 gnou. All rights reserved. // #import "MainStoriesViewController.h" #import "TitleCell.h" #import "Story.h" #import #import "AppDelegate.h" //#import "BodyViewController.h" #import "Date.h" #import #import #import "NetworkClient.h" #import #import "ContentViewController.h" #define HEIGHT_OF_SECTION_HEADER 37.5f @interface MainStoriesViewController () @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController; @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; @property (strong, nonatomic) IBOutlet UIView *view; @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (nonatomic, strong) NSDateFormatter *dateFormatter; @property (nonatomic, strong) AppDelegate *appDelegate; @property (nonatomic) CGFloat screenHeight; @property (nonatomic, strong) NetworkClient *networkClient; @end @implementation MainStoriesViewController - (void)setUp { // [[NSNotificationCenter defaultCenter] addObserverForName:StorysDatabaseAvailabilityNotification object:nil queue:nil usingBlock:^(NSNotification *note) { // self.managedObjectContext = note.userInfo[StorysDatabaseAvailabilityContext]; // }]; self.tableView.delegate = self; self.tableView.dataSource = self; self.appDelegate = [UIApplication sharedApplication].delegate; if (self.appDelegate.managedObjectContext) { self.managedObjectContext = self.appDelegate.managedObjectContext; } else { NSLog(@"not managedObjectContext in appDelegate"); } self.dateFormatter = [[NSDateFormatter alloc] init]; self.dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]; self.dateFormatter.dateStyle = NSDateFormatterFullStyle; self.screenHeight = [UIScreen mainScreen].bounds.size.height; self.networkClient = [[NetworkClient alloc] init]; } - (void)awakeFromNib { [self setUp]; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { [self setUp]; } return self; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.navigationController setNavigationBarHidden:NO animated:animated]; } - (void)viewDidLoad { [super viewDidLoad]; self.sideBarButton.target = self.revealViewController; self.sideBarButton.action = @selector(revealToggle:); [self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.navigationController setNavigationBarHidden:YES animated:animated]; } - (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext { _managedObjectContext = managedObjectContext; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Story" inManagedObjectContext:managedObjectContext]; [fetchRequest setEntity:entity]; [fetchRequest setPredicate:nil]; // Specify how the fetched objects should be sorted NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"gaPrefix" ascending:NO]; [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"date.dateString" cacheName:nil]; } - (void)setFetchedResultsController:(NSFetchedResultsController *)newfrc { _fetchedResultsController = newfrc; _fetchedResultsController.delegate = self; [self performFetch]; } #pragma mark - Fetching - (void)performFetch { if (self.fetchedResultsController) { NSError *error; BOOL success = [self.fetchedResultsController performFetch:&error]; if (!success) NSLog(@"[%@ %@] performFetch: failed", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); if (error) { NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]); } } [self.tableView reloadData]; } #pragma mark - UITableViewDataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { NSInteger sections = [[self.fetchedResultsController sections] count]; return sections; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSInteger rows = 0; if ([[self.fetchedResultsController sections] count] > 0) { id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; rows = [sectionInfo numberOfObjects]; } return rows; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { Story *story = [self.fetchedResultsController objectAtIndexPath:indexPath]; NSString *titleString = story.title; NSString *imageURL = story.imageURL; TitleCell *cell; if (imageURL) { cell = (TitleCell *)[tableView dequeueReusableCellWithIdentifier:@"TitleCell" forIndexPath:indexPath]; [cell.titleImageView sd_setImageWithURL:[NSURL URLWithString:imageURL] placeholderImage:[UIImage imageNamed:@"placeholder"]]; } else { cell = (TitleCell *)[tableView dequeueReusableCellWithIdentifier:@"TitleCellWithoutImage" forIndexPath:indexPath]; } cell.titleLabel.text = titleString; //[self configureCell:cell atIndexPath:indexPath]; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 90.0f; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (section == 0) { return 0.0f; } else { return HEIGHT_OF_SECTION_HEADER; } } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if (section == 0) { return nil; } CGRect headerFrame = CGRectMake(0, 0, tableView.frame.size.width, HEIGHT_OF_SECTION_HEADER); UIView *sectionHeaderView = [[UIView alloc] initWithFrame:headerFrame]; sectionHeaderView.backgroundColor = [self.appDelegate tintColor]; NSString *headerString = [[[self.fetchedResultsController sections] objectAtIndex:section] name]; UILabel *headerLabel = [[UILabel alloc] init]; NSString *displayText = [self displaySectionHeaderString:headerString]; headerLabel.text = displayText; [headerLabel sizeToFit]; [sectionHeaderView addSubview:headerLabel]; headerLabel.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:headerLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:sectionHeaderView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]; [sectionHeaderView addConstraint:centerX]; NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:headerLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:sectionHeaderView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]; [sectionHeaderView addConstraint:centerY]; return sectionHeaderView; } #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { // Total sections number NSInteger sectionsNum = [[self.fetchedResultsController sections] count]; // Total rows number in current section NSInteger rowsNum = 0; if ([[self.fetchedResultsController sections] count] > 0) { id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:indexPath.section]; rowsNum = [sectionInfo numberOfObjects]; } // check if this is the end of tableView if ((indexPath.section == (sectionsNum - 1)) && (indexPath.row == (rowsNum - 1))) { Story *story = [self.fetchedResultsController objectAtIndexPath:indexPath]; Date *currentDate = story.date; NSString *currentDateString = currentDate.dateString; [[self.networkClient fetchAndSaveStoriesBeforeCertainDate:currentDateString intoManagedObjectContext:self.managedObjectContext] subscribeError:^(NSError *error) { [TSMessage showNotificationInViewController:self.navigationController title:@"ERROR" subtitle:error.localizedDescription type:TSMessageNotificationTypeError]; }]; } } #pragma mark - NSFetchedResultsControllerDelegate - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { [self.tableView beginUpdates]; } - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { [self.tableView endUpdates]; } #pragma mark- Useful Functions // //- (void)configureCell:(TitleCell *)cell atIndexPath:(NSIndexPath *)indexPath { // Story *story = [self.fetchedResultsController objectAtIndexPath:indexPath]; // cell.titleLabel.text = story.title; // NSString *imageURL = story.imageURL; // if (!imageURL) { // NSLog(@"No image"); // NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:cell.titleImageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; // [cell addConstraint:constraint]; // } else { // [cell.titleImageView sd_setImageWithURL:[NSURL URLWithString:story.imageURL] placeholderImage:[UIImage imageNamed:@"placeholder"]]; // } //} - (NSString *)displaySectionHeaderString:(NSString *)dateString { if ([self.appDelegate isValidDateString:dateString]) { if ([dateString isEqualToString:[self.appDelegate dateStringOfToday]]) { return @"今日热门"; } self.dateFormatter.dateFormat = @"yyyyMMdd"; NSDate *date = [self.dateFormatter dateFromString:dateString]; NSString *dateFormat; NSString *dateComponent = @"MMMd EEEE"; NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]; dateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponent options:0 locale:locale]; [self.dateFormatter setDateFormat:dateFormat]; return [self.dateFormatter stringFromDate:date]; } return nil; } #pragma mark - navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // if ([segue.identifier isEqualToString:@"Goto News Body"]) { //BodyViewController *bodyVC = segue.destinationViewController; ContentViewController *contentVC = segue.destinationViewController; NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; Story *story = [self.fetchedResultsController objectAtIndexPath:indexPath]; //bodyVC.id = story.id; contentVC.id = story.id; // } } #pragma mark - UIScrollViewDelegate // 把contentView向上移动一个HEIGHT_OF_SECTION_HEADER的高度, // 以防止sectionHeaderView卡在navigationBar下面 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat sectionHeaderHeight = HEIGHT_OF_SECTION_HEADER; if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) { scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0); } else if (scrollView.contentOffset.y>=sectionHeaderHeight) { scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0); } } - (IBAction)getLatestStories:(id)sender { [[self.networkClient fetchAndSaveLatestStoriesIntoManagedObjectContext:self.managedObjectContext] subscribeError:^(NSError *error) { NSLog(@"error : %@", error.localizedDescription); }]; } @end ================================================ FILE: FakeZhihuDaily/NetworkClient.h ================================================ // // NetworkClient.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import #import #import @interface NetworkClient : NSObject - (RACSignal *)fetchAndSaveLatestStoriesIntoManagedObjectContext:(NSManagedObjectContext *)context; - (RACSignal *)fetchAndSaveStoriesBeforeCertainDate:(NSString *)dateString intoManagedObjectContext:(NSManagedObjectContext *)context; - (RACSignal *)fetchAndSaveThemesIntoManagedObjectContext:(NSManagedObjectContext *)context; - (RACSignal *)fetchAndSaveThemeStoriesWithThemeID:(NSUInteger)themeID intoMangedObjectContext:(NSManagedObjectContext *)context; - (RACSignal *)fetchJSONFromURL:(NSURL *)url; @end ================================================ FILE: FakeZhihuDaily/NetworkClient.m ================================================ // // NetworkClient.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import "NetworkClient.h" #import "Story+Create.h" #import "ThemeStory+Create.h" #import "AppDelegate.h" #import "Theme+Create.h" #import "FZDError.h" @interface NetworkClient () @property (nonatomic, strong) NSURLSession *session; @property (nonatomic, strong) AppDelegate *appDelegate; @end @implementation NetworkClient - (id)init { if (self = [super init]) { NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; _session = [NSURLSession sessionWithConfiguration:config]; self.appDelegate = [UIApplication sharedApplication].delegate; } return self; } #pragma mark - Fetch&Save Latest Stories - (RACSignal *)fetchAndSaveLatestStoriesIntoManagedObjectContext:(NSManagedObjectContext *)context { return [[self fetchLatestStories] flattenMap:^RACStream *(NSDictionary *jsonDictionary) { return [self saveStories:jsonDictionary intoManagedObjectContext:context]; }]; } - (RACSignal *)saveStories:(NSDictionary *)storiesDictionary intoManagedObjectContext:(NSManagedObjectContext *)context { return [RACSignal createSignal:^RACDisposable *(id subscriber) { NSString *dateString = storiesDictionary[@"date"]; NSArray *storiesArray = storiesDictionary[@"stories"]; [context performBlock:^{ NSError *saveError = nil; [Story loadStorysFromArray:storiesArray withDateString:dateString intoManagedObjectContext:context]; [context save:&saveError]; if (saveError) { [subscriber sendError:saveError]; } else { [subscriber sendCompleted]; } }]; return nil; }]; } - (RACSignal *)fetchLatestStories { NSString *urlString = @"http://news-at.zhihu.com/api/3/news/latest"; NSURL *url = [NSURL URLWithString:urlString]; return [self fetchJSONFromURL:url]; } #pragma mark - Fetch&Save Stories Before a Date - (RACSignal *)fetchAndSaveStoriesBeforeCertainDate:(NSString *)dateString intoManagedObjectContext:(NSManagedObjectContext *)context { return [[self fetchStoriesBeforCertainDate:dateString] flattenMap:^RACStream *(NSDictionary *jsonDictionary) { return [self saveStories:jsonDictionary intoManagedObjectContext:context]; }]; } - (RACSignal *)fetchStoriesBeforCertainDate:(NSString *)dateString { if (![self.appDelegate isValidDateString:dateString]) { [RACSignal createSignal:^RACDisposable *(id subscriber) { NSDictionary *userInfo = @{NSLocalizedDescriptionKey:NSLocalizedString(@"not a valid date string", nil)}; NSError *notValidDateStringError = [NSError errorWithDomain:FZDErrorDomain code:FZDInvalidDateString userInfo:userInfo]; [subscriber sendError:notValidDateStringError]; return nil; }]; } else { NSString *urlString = [NSString stringWithFormat:@"http://news.at.zhihu.com/api/3/news/before/%@", dateString]; NSURL *url = [NSURL URLWithString:urlString]; return [self fetchJSONFromURL:url]; } return nil; } #pragma mark - Fetch&Save Themes List - (RACSignal *)fetchAndSaveThemesIntoManagedObjectContext:(NSManagedObjectContext *)context { return [[self fetchThemes] flattenMap:^RACStream *(NSDictionary *jsonDictionary) { return [self saveThemesList:jsonDictionary intoManagedObjectContext:context]; }]; } - (RACSignal *)saveThemesList:(NSDictionary *)themesDictionary intoManagedObjectContext:(NSManagedObjectContext *)context { return [RACSignal createSignal:^RACDisposable *(id subscriber) { NSArray *themeArray = themesDictionary[@"others"]; [context performBlock:^{ [Theme loadThemesWithThemesArray:themeArray intoManagedObjectContext:context]; NSError *saveError = nil; [context save:&saveError]; if (saveError) { [subscriber sendError:saveError]; } else { [subscriber sendCompleted]; } }]; return nil; }]; } - (RACSignal *)fetchThemes { NSString *urlString = @"http://news-at.zhihu.com/api/3/themes"; NSURL *url = [NSURL URLWithString:urlString]; return [self fetchJSONFromURL:url]; } #pragma mark - Fetch&Save Theme Stories - (RACSignal *)fetchAndSaveThemeStoriesWithThemeID:(NSUInteger)themeID intoMangedObjectContext:(NSManagedObjectContext *)context { return [[self fetchStoriesOfCertainTheme:themeID] flattenMap:^RACStream *(NSDictionary *jsonDictionary) { return [self saveCertainThemeStories:jsonDictionary withThemeID:themeID intoManagedObjectContext:context]; }]; } - (RACSignal *)saveCertainThemeStories:(NSDictionary *)themeStoriesDictionary withThemeID:(NSUInteger)themeID intoManagedObjectContext:(NSManagedObjectContext *)context { return [RACSignal createSignal:^RACDisposable *(id subscriber) { NSArray *themeStoriesArray = themeStoriesDictionary[@"stories"]; [context performBlock:^{ [ThemeStory loadThemeStoriesFromArray:themeStoriesArray withThemeID:themeID intoManagedObjectContext:context]; NSError *saveError = nil; [context save:&saveError]; if (saveError) { [subscriber sendError:saveError]; } else { [subscriber sendCompleted]; } }]; return nil; }]; } - (RACSignal *)fetchStoriesOfCertainTheme:(NSUInteger)themeID { NSString *urlString = [NSString stringWithFormat:@"http://news-at.zhihu.com/api/3/theme/%lu", themeID]; NSURL *url = [NSURL URLWithString:urlString]; return [self fetchJSONFromURL:url]; } - (RACSignal *)fetchJSONFromURL:(NSURL *)url { //NSLog(@"Fetching: %@",url.absoluteString); return [[RACSignal createSignal:^RACDisposable *(id subscriber) { NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (! error) { NSError *jsonError = nil; id json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError]; if (! jsonError) { [subscriber sendNext:json]; } else { [subscriber sendError:jsonError]; } } else { [subscriber sendError:error]; } [subscriber sendCompleted]; }]; [dataTask resume]; return [RACDisposable disposableWithBlock:^{ [dataTask cancel]; }]; }] doError:^(NSError *error) { NSLog(@"%@",error); }]; } @end ================================================ FILE: FakeZhihuDaily/NetworkManager.h ================================================ // // Manager.h // FakeZhihuDaily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @interface NetworkManager : NSObject + (instancetype)sharedManager; //- (RACSignal *)syncTitles; - (void)trigger; @end ================================================ FILE: FakeZhihuDaily/NetworkManager.m ================================================ // // Manager.m // FakeZhihuDaily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import "NetworkManager.h" #import "Title.h" @import CoreData; #import "AppDelegate.h" #import "Story.h" @interface NetworkManager () @property (nonatomic, strong) NSURLSession *session; @property (nonatomic, strong) NSManagedObjectContext *context; @end @implementation NetworkManager + (instancetype)sharedManager { static NetworkManager *sharedManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedManager = [[self alloc] init]; }); return sharedManager; } - (instancetype)init { self = [super init]; if (self) { // Do some init work here NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; self.session = [NSURLSession sessionWithConfiguration:config]; AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; // self.context = appDelegate.managedObjectContext; } return self; } - (RACSignal *)syncTitles { NSURL *url = [NSURL URLWithString:@"http://news-at.zhihu.com/api/3/news/latest"]; return [RACSignal createSignal:^RACDisposable *(id subscriber) { NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse *resp = (NSHTTPURLResponse *)response; NSLog(@"response's statusCode: %ld", (long)resp.statusCode); if (!error) { NSError *jsonError; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError]; if (!jsonError) { //NSError *mtlError; NSArray *jsonArray = dict[@"stories"]; [self saveTitlesArray:jsonArray]; [subscriber sendCompleted]; // NSArray * titlesArray = [MTLJSONAdapter modelsOfClass:[Title class] fromJSONArray:jsonArray error:&mtlError]; // if (!mtlError) { // //[subscriber sendNext:titlesArray]; // [self saveTitlesArray:titlesArray]; // [subscriber sendCompleted]; // } else { // [subscriber sendError:mtlError]; // } } else { NSLog(@"%@", jsonError.userInfo); [subscriber sendError:jsonError]; } } else { [subscriber sendError:error]; } [subscriber sendCompleted]; }]; [dataTask resume]; return [RACDisposable disposableWithBlock:^{ [dataTask cancel]; }]; }]; } - (void)saveTitlesArray:(NSArray *)titlesArray { for (NSDictionary *title in titlesArray) { Story *story = [NSEntityDescription insertNewObjectForEntityForName:@"Story" inManagedObjectContext:self.context]; story.id = title[@"id"]; story.title = title[@"title"]; story.imageURL = title[@"images"][0]; story.shareURL = title[@"share_url"]; story.isRead = @(NO); NSError *saveError; [self.context save:&saveError]; } } - (void)trigger { [[self syncTitles] subscribeError:^(NSError *error) { NSLog(@"Error : %@", error); } completed:^{ NSLog(@"Completion"); }]; } @end ================================================ FILE: FakeZhihuDaily/SideBarTableViewController.h ================================================ // // SideBarTableViewController.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/12. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @interface SideBarTableViewController : UITableViewController @end ================================================ FILE: FakeZhihuDaily/SideBarTableViewController.m ================================================ // // SideBarTableViewController.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/12. // Copyright (c) 2014年 gnou. All rights reserved. // #import "SideBarTableViewController.h" #import "AppDelegate.h" #import "Theme.h" #import #import "MainStoriesViewController.h" #import "ThemeStoriesViewController.h" @interface SideBarTableViewController () @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController; @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; @property (nonatomic, strong) AppDelegate *appDelegate; @property (nonatomic, strong) NSArray *menuItems; @end @implementation SideBarTableViewController - (void)setUp { self.appDelegate = [UIApplication sharedApplication].delegate; if (self.appDelegate.managedObjectContext) { self.managedObjectContext = self.appDelegate.managedObjectContext; } else { NSLog(@"not managedObjectContext in appDelegate"); } } - (void)awakeFromNib { [self setUp]; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { [self setUp]; } return self; } - (void)viewDidLoad { [super viewDidLoad]; // Uncomment the following line to preserve selection between presentations. // self.clearsSelectionOnViewWillAppear = NO; // Uncomment the following line to display an Edit button in the navigation bar for this view controller. // self.navigationItem.rightBarButtonItem = self.editButtonItem; //self.tableView.rowHeight = 44; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext { _managedObjectContext = managedObjectContext; NSFetchRequest *request = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Theme" inManagedObjectContext:managedObjectContext]; [request setEntity:entity]; [request setPredicate:nil]; NSSortDescriptor *sortDescription = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:NO]; [request setSortDescriptors:@[sortDescription]]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil]; } - (void)setFetchedResultsController:(NSFetchedResultsController *)fetchedResultsController { _fetchedResultsController = fetchedResultsController; _fetchedResultsController.delegate = self; [self performFetch]; } - (void)performFetch { NSError *error; BOOL success = [self.fetchedResultsController performFetch:&error]; if (!success) NSLog(@"[%@ %@] performFetch: failed", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); if (error) { NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]); } [self.tableView reloadData]; } #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. NSInteger rows = 0; if ([[self.fetchedResultsController sections] count] > 0) { id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; rows = [sectionInfo numberOfObjects]; } return rows + 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = nil; switch (indexPath.row) { case 0: cellIdentifier = @"Home"; break; default: cellIdentifier = @"Theme"; break; } UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; // Configure the cell... if (indexPath.row == 0) { cell.textLabel.text = @"首页"; } else { NSIndexPath *objectIndexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section]; Theme *theme = [self.fetchedResultsController objectAtIndexPath:objectIndexPath]; cell.textLabel.text = theme.name; } return cell; } #pragma mark - NSFetchedResultsControllerDelegate - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { [self.tableView beginUpdates]; } - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { [self.tableView endUpdates]; } #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController; Theme *theme = nil; if (indexPath.row > 0) { NSIndexPath *objectIndexPath = [NSIndexPath indexPathForRow:indexPath.row-1 inSection:indexPath.section]; theme = [self.fetchedResultsController objectAtIndexPath:objectIndexPath]; } if ([[destViewController childViewControllers].firstObject isKindOfClass:[ThemeStoriesViewController class]]) { ThemeStoriesViewController *themeVC = (ThemeStoriesViewController *)[destViewController childViewControllers][0]; themeVC.themeID = theme.id.integerValue; themeVC.title = theme.name; } } @end ================================================ FILE: FakeZhihuDaily/StoriesList.swift ================================================ // // StoriesList.swift // FakeZhihuDaily // // Created by CuiMingyu on 15/1/9. // Copyright (c) 2015年 gnou. All rights reserved. // import Foundation ================================================ FILE: FakeZhihuDaily/Story+Create.h ================================================ // // Story+Create.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/6. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Story.h" @interface Story (Create) + (Story *)storyWithStoryInfo:(NSDictionary *)storyDictionary withDateString:(NSString *)dateString inManagedObjectContext:(NSManagedObjectContext *)context; + (void)loadStorysFromArray:(NSArray *)storyArray withDateString:(NSString *)dateString intoManagedObjectContext:(NSManagedObjectContext *)context; @end ================================================ FILE: FakeZhihuDaily/Story+Create.m ================================================ // // Story+Create.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/6. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Story+Create.h" #import "Date+Create.h" @implementation Story (Create) + (Story *)storyWithStoryInfo:(NSDictionary *)storyDictionary withDateString:(NSString *)dateString inManagedObjectContext:(NSManagedObjectContext *)context { Story *story = nil; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"Story" inManagedObjectContext:context]; [fetchRequest setEntity:entity]; // Specify criteria for filtering which objects to fetch NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id = %@", storyDictionary[@"id"]]; [fetchRequest setPredicate:predicate]; // Specify how the fetched objects should be sorted NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"gaPrefix" ascending:YES]; [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; NSError *error = nil; NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error]; if (fetchedObjects == nil || error || [fetchedObjects count] > 1) { NSLog(@"Error : fetch object from DB error"); } else if ([fetchedObjects count]) { return [fetchedObjects firstObject]; } else { story = [NSEntityDescription insertNewObjectForEntityForName:@"Story" inManagedObjectContext:context]; story.id = storyDictionary[@"id"]; story.title = storyDictionary[@"title"]; story.gaPrefix = storyDictionary[@"ga_prefix"]; story.imageURL = storyDictionary[@"images"][0]; story.shareURL = storyDictionary[@"share_url"]; story.date = [Date dateWithDateString:dateString inManagedObjectContext:context]; } return story; } + (void)loadStorysFromArray:(NSArray *)storyArray withDateString:(NSString *)dateString intoManagedObjectContext:(NSManagedObjectContext *)context { for (NSDictionary *story in storyArray) { [self storyWithStoryInfo:story withDateString:(NSString *)dateString inManagedObjectContext:context]; } } @end ================================================ FILE: FakeZhihuDaily/Story.h ================================================ // // Story.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/10. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @class Date; @interface Story : NSManagedObject @property (nonatomic, retain) NSString * gaPrefix; @property (nonatomic, retain) NSNumber * id; @property (nonatomic, retain) NSString * imageURL; @property (nonatomic, retain) NSNumber * isRead; @property (nonatomic, retain) NSString * shareURL; @property (nonatomic, retain) NSString * title; @property (nonatomic, retain) Date *date; @end ================================================ FILE: FakeZhihuDaily/Story.m ================================================ // // Story.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/10. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Story.h" #import "Date.h" @implementation Story @dynamic gaPrefix; @dynamic id; @dynamic imageURL; @dynamic isRead; @dynamic shareURL; @dynamic title; @dynamic date; @end ================================================ FILE: FakeZhihuDaily/Theme+Create.h ================================================ // // Theme+Create.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/14. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Theme.h" @interface Theme (Create) + (Theme *)themeWithThemeInfo:(NSDictionary *)info inManagedObjectContext:(NSManagedObjectContext *)context; + (void)loadThemesWithThemesArray:(NSArray *)array intoManagedObjectContext:(NSManagedObjectContext *)context; @end ================================================ FILE: FakeZhihuDaily/Theme+Create.m ================================================ // // Theme+Create.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/14. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Theme+Create.h" @implementation Theme (Create) + (Theme *)themeWithThemeInfo:(NSDictionary *)info inManagedObjectContext:(NSManagedObjectContext *)context { Theme *theme = nil; NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Theme"]; request.predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"id = %@", info[@"id"]]]; NSError *error; NSArray *resultArray = [context executeFetchRequest:request error:&error]; if (!resultArray || error || [resultArray count] > 1) { NSLog(@"ERROR in %s", __FUNCTION__); } else if ([resultArray count]) { theme = resultArray.firstObject; } else if (![resultArray count]) { theme = [NSEntityDescription insertNewObjectForEntityForName:@"Theme" inManagedObjectContext:context]; theme.id = info[@"id"]; theme.name = info[@"name"]; theme.descrip = info[@"description"]; theme.imageURL = info[@"image"]; theme.color = info[@"color"]; } return theme; } + (void)loadThemesWithThemesArray:(NSArray *)array intoManagedObjectContext:(NSManagedObjectContext *)context { for (NSDictionary *dict in array) { [self themeWithThemeInfo:dict inManagedObjectContext:context]; } } @end ================================================ FILE: FakeZhihuDaily/Theme.h ================================================ // // Theme.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @class ThemeStory; @interface Theme : NSManagedObject @property (nonatomic, retain) NSNumber * color; @property (nonatomic, retain) NSString * descrip; @property (nonatomic, retain) NSNumber * id; @property (nonatomic, retain) NSString * imageURL; @property (nonatomic, retain) NSString * name; @property (nonatomic, retain) NSSet *stories; @end @interface Theme (CoreDataGeneratedAccessors) - (void)addStoriesObject:(ThemeStory *)value; - (void)removeStoriesObject:(ThemeStory *)value; - (void)addStories:(NSSet *)values; - (void)removeStories:(NSSet *)values; @end ================================================ FILE: FakeZhihuDaily/Theme.m ================================================ // // Theme.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Theme.h" #import "ThemeStory.h" @implementation Theme @dynamic color; @dynamic descrip; @dynamic id; @dynamic imageURL; @dynamic name; @dynamic stories; @end ================================================ FILE: FakeZhihuDaily/ThemeBodyViewController.h ================================================ // // ThemeBodyViewController.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/18. // Copyright (c) 2014年 gnou. All rights reserved. // #import @interface ThemeBodyViewController : UIViewController @property (nonatomic, strong) NSNumber *id; @end ================================================ FILE: FakeZhihuDaily/ThemeBodyViewController.m ================================================ // // ThemeBodyViewController.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/18. // Copyright (c) 2014年 gnou. All rights reserved. // #import "ThemeBodyViewController.h" #import "NetworkClient.h" #import "ContentViewController.h" #import #import @interface ThemeBodyViewController () @property (weak, nonatomic) IBOutlet UIWebView *webView; @property (weak, nonatomic) IBOutlet UIActivityIndicatorView *indicator; @property (nonatomic, strong) NSURL *url; //@property (nonatomic, strong) NSURLSession *session; @property (nonatomic, strong) NetworkClient *networkClient; @end @implementation ThemeBodyViewController - (void)setUp { self.networkClient = [[NetworkClient alloc] init]; } - (void)awakeFromNib { [self setUp]; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { [self setUp]; } return self; } - (void)setId:(NSNumber *)id { _id = id; NSString *urlString = [NSString stringWithFormat:@"http://news-at.zhihu.com/api/3/news/%@", id.stringValue]; self.url = [NSURL URLWithString:urlString]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self.indicator startAnimating]; self.webView.delegate = self; [self.navigationController.interactivePopGestureRecognizer setDelegate:nil]; @weakify(self) [[[[[RACObserve(self, url) ignore:nil] flattenMap:^RACStream *(NSURL *url) { return [self.networkClient fetchJSONFromURL:url]; }] deliverOn:[RACScheduler mainThreadScheduler] ] map:^id(NSDictionary *jsonDictionary) { ContentViewController *bodyVC = [[ContentViewController alloc] init]; return [bodyVC generateWebPageFromDictionary:jsonDictionary]; }] subscribeNext:^(NSString *htmlString) { @strongify(self) [self.indicator stopAnimating]; [self.indicator removeFromSuperview]; [self.webView loadHTMLString:htmlString baseURL:nil]; } error:^(NSError *error) { [TSMessage showNotificationInViewController:self title:@"ERROR" subtitle:error.localizedDescription type:TSMessageNotificationTypeError]; }]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ #pragma mark - UIWebViewDelegate -(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType { if ( inType == UIWebViewNavigationTypeLinkClicked ) { [[UIApplication sharedApplication] openURL:[inRequest URL]]; return NO; } return YES; } @end ================================================ FILE: FakeZhihuDaily/ThemeStoriesViewController.h ================================================ // // ThemeStoriesViewController.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @interface ThemeStoriesViewController : UIViewController @property (weak, nonatomic) IBOutlet UIBarButtonItem *sideBarButton; @property (nonatomic) NSUInteger themeID; @end ================================================ FILE: FakeZhihuDaily/ThemeStoriesViewController.m ================================================ // // ThemeStoriesViewController.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import "ThemeStoriesViewController.h" #import "AppDelegate.h" #import "NetworkClient.h" #import #import "TitleCell.h" #import "ThemeStory.h" #import //#import "BodyViewController.h" #import #import "ThemeBodyViewController.h" @interface ThemeStoriesViewController () @property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController; @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; @property (strong, nonatomic) IBOutlet UIView *view; @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (nonatomic, strong) AppDelegate *appDelegate; //@property (nonatomic) CGFloat screenHeight; @property (nonatomic, strong) NetworkClient *networkClient; @end @implementation ThemeStoriesViewController - (void)setUp { self.tableView.delegate = self; self.tableView.dataSource = self; self.appDelegate = [UIApplication sharedApplication].delegate; if (self.appDelegate.managedObjectContext) { self.managedObjectContext = self.appDelegate.managedObjectContext; } else { NSLog(@"not managedObjectContext in appDelegate"); } self.networkClient = [[NetworkClient alloc] init]; } - (void)awakeFromNib { [self setUp]; } - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { [self setUp]; } return self; } - (void)setThemeID:(NSUInteger)themeID { _themeID = themeID; [self fetchThemeStories]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"ThemeStory" inManagedObjectContext:self.managedObjectContext]; [fetchRequest setEntity:entity]; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"blongsTo.id = %lu", self.themeID]; // Specify how the fetched objects should be sorted NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:NO]; [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [self.navigationController setNavigationBarHidden:NO animated:animated]; } - (void)viewDidLoad { [super viewDidLoad]; self.sideBarButton.target = self.revealViewController; self.sideBarButton.action = @selector(revealToggle:); [self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer]; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.navigationController setNavigationBarHidden:YES animated:animated]; } - (void)setFetchedResultsController:(NSFetchedResultsController *)newfrc { _fetchedResultsController = newfrc; _fetchedResultsController.delegate = self; [self performFetch]; } #pragma mark - Fetching - (void)performFetch { if (self.fetchedResultsController) { NSError *error; BOOL success = [self.fetchedResultsController performFetch:&error]; if (!success) NSLog(@"[%@ %@] performFetch: failed", NSStringFromClass([self class]), NSStringFromSelector(_cmd)); if (error) { NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]); } } [self.tableView reloadData]; } #pragma mark - UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSInteger rows = 0; if ([[self.fetchedResultsController sections] count] > 0) { id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section]; rows = [sectionInfo numberOfObjects]; } return rows; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ThemeStory *themeStory = [self.fetchedResultsController objectAtIndexPath:indexPath]; NSString *titleString = themeStory.title; NSString *imageURL = themeStory.imageURL; TitleCell *cell; if (imageURL) { cell = (TitleCell *)[tableView dequeueReusableCellWithIdentifier:@"TitleCell" forIndexPath:indexPath]; [cell.titleImageView sd_setImageWithURL:[NSURL URLWithString:imageURL] placeholderImage:[UIImage imageNamed:@"placeholder"]]; } else { cell = (TitleCell *)[tableView dequeueReusableCellWithIdentifier:@"TitleCellWithoutImage" forIndexPath:indexPath]; } cell.titleLabel.text = titleString; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 90.0f; } #pragma mark - NSFetchedResultsControllerDelegate - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { [self.tableView beginUpdates]; } - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; } } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { [self.tableView endUpdates]; } #pragma mark - navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { ThemeBodyViewController *bodyVC = segue.destinationViewController; NSIndexPath *indexPath = [self.tableView indexPathForCell:sender]; ThemeStory *story = [self.fetchedResultsController objectAtIndexPath:indexPath]; bodyVC.id = story.id; } - (void)fetchThemeStories { [[self.networkClient fetchAndSaveThemeStoriesWithThemeID:self.themeID intoMangedObjectContext:self.managedObjectContext] subscribeError:^(NSError *error) { [TSMessage showNotificationInViewController:self.navigationController title:@"ERROR" subtitle:error.localizedDescription type:TSMessageNotificationTypeError]; }]; } @end ================================================ FILE: FakeZhihuDaily/ThemeStory+Create.h ================================================ // // ThemeStory+Create.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import "ThemeStory.h" @interface ThemeStory (Create) + (ThemeStory *)themeStoryWithStoryInfo:(NSDictionary *)storyDictionary withThemeID:(NSUInteger)id inManagedObjectContext:(NSManagedObjectContext *)context; + (void)loadThemeStoriesFromArray:(NSArray *)array withThemeID:(NSUInteger)id intoManagedObjectContext:(NSManagedObjectContext *)context; @end ================================================ FILE: FakeZhihuDaily/ThemeStory+Create.m ================================================ // // ThemeStory+Create.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import "ThemeStory+Create.h" #import "Theme+Create.m" @implementation ThemeStory (Create) + (ThemeStory *)themeStoryWithStoryInfo:(NSDictionary *)storyDictionary withThemeID:(NSUInteger)id inManagedObjectContext:(NSManagedObjectContext *)context { ThemeStory *story = nil; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"ThemeStory"]; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"id = %@", storyDictionary[@"id"]]; NSError *error; NSArray *matchedResult = [context executeFetchRequest:fetchRequest error:&error]; if (matchedResult == nil || error || [matchedResult count] > 1) { NSLog(@"Error in %s", __FUNCTION__); } else if ([matchedResult count]) { story = matchedResult.firstObject; } else { story = [NSEntityDescription insertNewObjectForEntityForName:@"ThemeStory" inManagedObjectContext:context]; story.id = storyDictionary[@"id"]; story.shareURL = storyDictionary[@"share_url"]; story.title = storyDictionary[@"title"]; story.imageURL = storyDictionary[@"images"][0]; NSDictionary *themeDictionary = @{@"id":[NSNumber numberWithUnsignedLong:id]}; story.blongsTo = [Theme themeWithThemeInfo:themeDictionary inManagedObjectContext:context]; } return story; } + (void)loadThemeStoriesFromArray:(NSArray *)array withThemeID:(NSUInteger)id intoManagedObjectContext:(NSManagedObjectContext *)context { for (NSDictionary *dict in array) { [self themeStoryWithStoryInfo:dict withThemeID:id inManagedObjectContext:context]; } } @end ================================================ FILE: FakeZhihuDaily/ThemeStory.h ================================================ // // Theme_Story.h // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @class Theme; @interface ThemeStory : NSManagedObject @property (nonatomic, retain) NSNumber * id; @property (nonatomic, retain) NSString * imageURL; @property (nonatomic, retain) NSNumber * isRead; @property (nonatomic, retain) NSString * shareURL; @property (nonatomic, retain) NSString * title; @property (nonatomic, retain) Theme *blongsTo; @end ================================================ FILE: FakeZhihuDaily/ThemeStory.m ================================================ // // Theme_Story.m // FakeZhihuDaily // // Created by CuiMingyu on 14/12/16. // Copyright (c) 2014年 gnou. All rights reserved. // #import "ThemeStory.h" #import "Theme.h" @implementation ThemeStory @dynamic id; @dynamic imageURL; @dynamic isRead; @dynamic shareURL; @dynamic title; @dynamic blongsTo; @end ================================================ FILE: FakeZhihuDaily/Title.h ================================================ // // Title.h // FakeZhihuDaily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import "MTLModel.h" #import @interface Title : MTLModel @property (nonatomic, strong) NSNumber *id; @property (nonatomic, strong) NSString *title; @property (nonatomic, strong) NSArray *imagesURL; @property (nonatomic, strong) NSString *shareURL; @end ================================================ FILE: FakeZhihuDaily/Title.m ================================================ // // Title.m // FakeZhihuDaily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import "Title.h" @implementation Title + (NSDictionary *)JSONKeyPathsByPropertyKey { return @{ @"id":@"id", @"title":@"title", @"imagesURL":@"images", @"shareURL":@"share_url", }; } @end ================================================ FILE: FakeZhihuDaily/TitleCell.h ================================================ // // TitleTableViewCell.h // Fake Zhihu Daily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import @interface TitleCell : UITableViewCell @property (weak, nonatomic) IBOutlet UILabel *titleLabel; @property (weak, nonatomic) IBOutlet UIImageView *titleImageView; @end ================================================ FILE: FakeZhihuDaily/TitleCell.m ================================================ // // TitleTableViewCell.m // Fake Zhihu Daily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import "TitleCell.h" @implementation TitleCell - (void)awakeFromNib { // Initialization code } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state } @end ================================================ FILE: FakeZhihuDaily/main.m ================================================ // // main.m // FakeZhihuDaily // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: FakeZhihuDaily.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 186896731A738D1D005EEDA7 /* TitleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 186896721A738D1D005EEDA7 /* TitleCell.m */; }; 4C2144071A39A72200757A36 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C2144061A39A72200757A36 /* Localizable.strings */; }; 4C32328D1A5BAD8200D63136 /* ContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C32328C1A5BAD8200D63136 /* ContentViewController.m */; }; 4C43BB8B1A5FA50F00371E89 /* StoriesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C43BB8A1A5FA50F00371E89 /* StoriesList.swift */; }; 4C5E0E441A42DB3D00E7934F /* ThemeBodyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5E0E431A42DB3D00E7934F /* ThemeBodyViewController.m */; }; 4C813F171A3D8BE60033D81C /* Theme+Create.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C813F161A3D8BE60033D81C /* Theme+Create.m */; }; 4C87F4D91A32EED6008A8555 /* AppDelegate+MOC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C87F4D81A32EED6008A8555 /* AppDelegate+MOC.m */; }; 4C87F4DD1A32F131008A8555 /* Story+Create.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C87F4DC1A32F131008A8555 /* Story+Create.m */; }; 4C87F4E61A32FE64008A8555 /* MainStoriesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C87F4E51A32FE64008A8555 /* MainStoriesViewController.m */; }; 4C9C8EF31A3FD450009AE2F9 /* ThemeStory.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C9C8EF21A3FD450009AE2F9 /* ThemeStory.m */; }; 4C9C8EF61A3FD467009AE2F9 /* Theme.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C9C8EF51A3FD467009AE2F9 /* Theme.m */; }; 4C9C8EFF1A3FE206009AE2F9 /* NetworkClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C9C8EFE1A3FE206009AE2F9 /* NetworkClient.m */; }; 4C9C8F021A400568009AE2F9 /* ThemeStory+Create.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C9C8F011A400568009AE2F9 /* ThemeStory+Create.m */; }; 4C9C8F051A40114F009AE2F9 /* ThemeStoriesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C9C8F041A40114F009AE2F9 /* ThemeStoriesViewController.m */; }; 4CB9CE811A5BD493001D4A3A /* ContentHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CB9CE801A5BD493001D4A3A /* ContentHeaderView.xib */; }; 4CB9CE841A5BD765001D4A3A /* ContentHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB9CE831A5BD765001D4A3A /* ContentHeaderView.m */; }; 4CBD5DFA1A3AF777001C6FC0 /* SideBarTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CBD5DF91A3AF777001C6FC0 /* SideBarTableViewController.m */; }; 4CF2D6E81A2874590080B019 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF2D6E71A2874590080B019 /* main.m */; }; 4CF2D6EB1A2874590080B019 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF2D6EA1A2874590080B019 /* AppDelegate.m */; }; 4CF2D6F11A2874590080B019 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4CF2D6EF1A2874590080B019 /* Main.storyboard */; }; 4CF2D6F31A2874590080B019 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4CF2D6F21A2874590080B019 /* Images.xcassets */; }; 4CF2D6F61A2874590080B019 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CF2D6F41A2874590080B019 /* LaunchScreen.xib */; }; 4CF2D7021A2874590080B019 /* FakeZhihuDailyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF2D7011A2874590080B019 /* FakeZhihuDailyTests.m */; }; 4CF2D71F1A288B610080B019 /* FakeZhihuDaily.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4CF2D71D1A288B610080B019 /* FakeZhihuDaily.xcdatamodeld */; }; 4CF59B651A37EB3400475CB7 /* Story.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF59B641A37EB3400475CB7 /* Story.m */; }; 4CF59B681A37EC3200475CB7 /* Date+Create.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF59B671A37EC3200475CB7 /* Date+Create.m */; }; 4CF59B6B1A37ED3100475CB7 /* Date.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF59B6A1A37ED3100475CB7 /* Date.m */; }; 6C3745A04615A235CADC83F5 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 277424DF40C7D10B7787200B /* libPods.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 4CF2D6FC1A2874590080B019 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4CF2D6DA1A2874590080B019 /* Project object */; proxyType = 1; remoteGlobalIDString = 4CF2D6E11A2874590080B019; remoteInfo = FakeZhihuDaily; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 0BCB7CE7308CCE271DCE5AFE /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 186896711A738D1D005EEDA7 /* TitleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TitleCell.h; sourceTree = ""; }; 186896721A738D1D005EEDA7 /* TitleCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TitleCell.m; sourceTree = ""; }; 277424DF40C7D10B7787200B /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 2BBB8199B14BBE8D0114A5B4 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 4C1660801A304CFE00D33092 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 4C2144061A39A72200757A36 /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; 4C32328B1A5BAD8200D63136 /* ContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentViewController.h; sourceTree = ""; }; 4C32328C1A5BAD8200D63136 /* ContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContentViewController.m; sourceTree = ""; }; 4C43BB891A5FA50F00371E89 /* FakeZhihuDaily-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "FakeZhihuDaily-Bridging-Header.h"; sourceTree = ""; }; 4C43BB8A1A5FA50F00371E89 /* StoriesList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoriesList.swift; sourceTree = ""; }; 4C5E0E411A42CC9900E7934F /* FZDError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FZDError.h; sourceTree = ""; }; 4C5E0E421A42DB3D00E7934F /* ThemeBodyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThemeBodyViewController.h; sourceTree = ""; }; 4C5E0E431A42DB3D00E7934F /* ThemeBodyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThemeBodyViewController.m; sourceTree = ""; }; 4C813F151A3D8BE60033D81C /* Theme+Create.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Theme+Create.h"; sourceTree = ""; }; 4C813F161A3D8BE60033D81C /* Theme+Create.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Theme+Create.m"; sourceTree = ""; }; 4C87F4D71A32EED6008A8555 /* AppDelegate+MOC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "AppDelegate+MOC.h"; sourceTree = ""; }; 4C87F4D81A32EED6008A8555 /* AppDelegate+MOC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "AppDelegate+MOC.m"; sourceTree = ""; }; 4C87F4DB1A32F131008A8555 /* Story+Create.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Story+Create.h"; sourceTree = ""; }; 4C87F4DC1A32F131008A8555 /* Story+Create.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Story+Create.m"; sourceTree = ""; }; 4C87F4E41A32FE64008A8555 /* MainStoriesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainStoriesViewController.h; sourceTree = ""; }; 4C87F4E51A32FE64008A8555 /* MainStoriesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainStoriesViewController.m; sourceTree = ""; }; 4C9C8EF11A3FD450009AE2F9 /* ThemeStory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThemeStory.h; sourceTree = ""; }; 4C9C8EF21A3FD450009AE2F9 /* ThemeStory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThemeStory.m; sourceTree = ""; }; 4C9C8EF41A3FD467009AE2F9 /* Theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Theme.h; sourceTree = ""; }; 4C9C8EF51A3FD467009AE2F9 /* Theme.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Theme.m; sourceTree = ""; }; 4C9C8EFD1A3FE206009AE2F9 /* NetworkClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkClient.h; sourceTree = ""; }; 4C9C8EFE1A3FE206009AE2F9 /* NetworkClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetworkClient.m; sourceTree = ""; }; 4C9C8F001A400568009AE2F9 /* ThemeStory+Create.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ThemeStory+Create.h"; sourceTree = ""; }; 4C9C8F011A400568009AE2F9 /* ThemeStory+Create.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ThemeStory+Create.m"; sourceTree = ""; }; 4C9C8F031A40114F009AE2F9 /* ThemeStoriesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThemeStoriesViewController.h; sourceTree = ""; }; 4C9C8F041A40114F009AE2F9 /* ThemeStoriesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThemeStoriesViewController.m; sourceTree = ""; }; 4CB9CE801A5BD493001D4A3A /* ContentHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContentHeaderView.xib; sourceTree = ""; }; 4CB9CE821A5BD765001D4A3A /* ContentHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentHeaderView.h; sourceTree = ""; }; 4CB9CE831A5BD765001D4A3A /* ContentHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContentHeaderView.m; sourceTree = ""; }; 4CBD5DF81A3AF777001C6FC0 /* SideBarTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SideBarTableViewController.h; sourceTree = ""; }; 4CBD5DF91A3AF777001C6FC0 /* SideBarTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SideBarTableViewController.m; sourceTree = ""; }; 4CF2D6E21A2874590080B019 /* FakeZhihuDaily.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FakeZhihuDaily.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4CF2D6E61A2874590080B019 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4CF2D6E71A2874590080B019 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 4CF2D6E91A2874590080B019 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 4CF2D6EA1A2874590080B019 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 4CF2D6F01A2874590080B019 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 4CF2D6F21A2874590080B019 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 4CF2D6F51A2874590080B019 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 4CF2D6FB1A2874590080B019 /* FakeZhihuDailyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FakeZhihuDailyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 4CF2D7001A2874590080B019 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4CF2D7011A2874590080B019 /* FakeZhihuDailyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FakeZhihuDailyTests.m; sourceTree = ""; }; 4CF2D71E1A288B610080B019 /* FakeZhihuDaily.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = FakeZhihuDaily.xcdatamodel; sourceTree = ""; }; 4CF59B631A37EB3400475CB7 /* Story.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Story.h; sourceTree = ""; }; 4CF59B641A37EB3400475CB7 /* Story.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Story.m; sourceTree = ""; }; 4CF59B661A37EC3200475CB7 /* Date+Create.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Date+Create.h"; sourceTree = ""; }; 4CF59B671A37EC3200475CB7 /* Date+Create.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Date+Create.m"; sourceTree = ""; }; 4CF59B691A37ED3100475CB7 /* Date.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Date.h; sourceTree = ""; }; 4CF59B6A1A37ED3100475CB7 /* Date.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Date.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 4CF2D6DF1A2874590080B019 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 6C3745A04615A235CADC83F5 /* libPods.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 4CF2D6F81A2874590080B019 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 37199B05F3DABB1AC06BEDA1 /* Frameworks */ = { isa = PBXGroup; children = ( 4C1660801A304CFE00D33092 /* CoreData.framework */, 277424DF40C7D10B7787200B /* libPods.a */, ); name = Frameworks; sourceTree = ""; }; 4C9C8EF71A3FD487009AE2F9 /* Data Models */ = { isa = PBXGroup; children = ( 4CF2D71D1A288B610080B019 /* FakeZhihuDaily.xcdatamodeld */, 4C9C8EF11A3FD450009AE2F9 /* ThemeStory.h */, 4C9C8EF21A3FD450009AE2F9 /* ThemeStory.m */, 4C9C8F001A400568009AE2F9 /* ThemeStory+Create.h */, 4C9C8F011A400568009AE2F9 /* ThemeStory+Create.m */, 4C9C8EF41A3FD467009AE2F9 /* Theme.h */, 4C9C8EF51A3FD467009AE2F9 /* Theme.m */, 4C813F151A3D8BE60033D81C /* Theme+Create.h */, 4C813F161A3D8BE60033D81C /* Theme+Create.m */, 4CF59B631A37EB3400475CB7 /* Story.h */, 4CF59B641A37EB3400475CB7 /* Story.m */, 4C87F4DB1A32F131008A8555 /* Story+Create.h */, 4C87F4DC1A32F131008A8555 /* Story+Create.m */, 4CF59B691A37ED3100475CB7 /* Date.h */, 4CF59B6A1A37ED3100475CB7 /* Date.m */, 4CF59B661A37EC3200475CB7 /* Date+Create.h */, 4CF59B671A37EC3200475CB7 /* Date+Create.m */, ); name = "Data Models"; sourceTree = ""; }; 4C9C8EF81A3FD4E3009AE2F9 /* View Controllers */ = { isa = PBXGroup; children = ( 186896711A738D1D005EEDA7 /* TitleCell.h */, 186896721A738D1D005EEDA7 /* TitleCell.m */, 4CBD5DF81A3AF777001C6FC0 /* SideBarTableViewController.h */, 4CBD5DF91A3AF777001C6FC0 /* SideBarTableViewController.m */, 4C87F4E41A32FE64008A8555 /* MainStoriesViewController.h */, 4C87F4E51A32FE64008A8555 /* MainStoriesViewController.m */, 4C32328B1A5BAD8200D63136 /* ContentViewController.h */, 4C32328C1A5BAD8200D63136 /* ContentViewController.m */, 4C43BB8A1A5FA50F00371E89 /* StoriesList.swift */, 4C9C8F031A40114F009AE2F9 /* ThemeStoriesViewController.h */, 4C9C8F041A40114F009AE2F9 /* ThemeStoriesViewController.m */, 4C5E0E421A42DB3D00E7934F /* ThemeBodyViewController.h */, 4C5E0E431A42DB3D00E7934F /* ThemeBodyViewController.m */, 4C43BB891A5FA50F00371E89 /* FakeZhihuDaily-Bridging-Header.h */, ); name = "View Controllers"; sourceTree = ""; }; 4C9C8EFC1A3FE1E8009AE2F9 /* Network Models */ = { isa = PBXGroup; children = ( 4C9C8EFD1A3FE206009AE2F9 /* NetworkClient.h */, 4C9C8EFE1A3FE206009AE2F9 /* NetworkClient.m */, ); name = "Network Models"; sourceTree = ""; }; 4CF2D6D91A2874590080B019 = { isa = PBXGroup; children = ( 4CF2D6E41A2874590080B019 /* FakeZhihuDaily */, 4CF2D6FE1A2874590080B019 /* FakeZhihuDailyTests */, 4CF2D6E31A2874590080B019 /* Products */, A5F13419D3ADD74DF689E684 /* Pods */, 37199B05F3DABB1AC06BEDA1 /* Frameworks */, ); sourceTree = ""; }; 4CF2D6E31A2874590080B019 /* Products */ = { isa = PBXGroup; children = ( 4CF2D6E21A2874590080B019 /* FakeZhihuDaily.app */, 4CF2D6FB1A2874590080B019 /* FakeZhihuDailyTests.xctest */, ); name = Products; sourceTree = ""; }; 4CF2D6E41A2874590080B019 /* FakeZhihuDaily */ = { isa = PBXGroup; children = ( 4CB9CE801A5BD493001D4A3A /* ContentHeaderView.xib */, 4CB9CE821A5BD765001D4A3A /* ContentHeaderView.h */, 4CB9CE831A5BD765001D4A3A /* ContentHeaderView.m */, 4C5E0E411A42CC9900E7934F /* FZDError.h */, 4CF2D6E91A2874590080B019 /* AppDelegate.h */, 4CF2D6EA1A2874590080B019 /* AppDelegate.m */, 4C87F4D71A32EED6008A8555 /* AppDelegate+MOC.h */, 4C87F4D81A32EED6008A8555 /* AppDelegate+MOC.m */, 4CF2D6EF1A2874590080B019 /* Main.storyboard */, 4C9C8EF71A3FD487009AE2F9 /* Data Models */, 4C9C8EF81A3FD4E3009AE2F9 /* View Controllers */, 4C9C8EFC1A3FE1E8009AE2F9 /* Network Models */, 4CF2D6F21A2874590080B019 /* Images.xcassets */, 4CF2D6F41A2874590080B019 /* LaunchScreen.xib */, 4CF2D6E51A2874590080B019 /* Supporting Files */, ); path = FakeZhihuDaily; sourceTree = ""; }; 4CF2D6E51A2874590080B019 /* Supporting Files */ = { isa = PBXGroup; children = ( 4CF2D6E61A2874590080B019 /* Info.plist */, 4C2144061A39A72200757A36 /* Localizable.strings */, 4CF2D6E71A2874590080B019 /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 4CF2D6FE1A2874590080B019 /* FakeZhihuDailyTests */ = { isa = PBXGroup; children = ( 4CF2D7011A2874590080B019 /* FakeZhihuDailyTests.m */, 4CF2D6FF1A2874590080B019 /* Supporting Files */, ); path = FakeZhihuDailyTests; sourceTree = ""; }; 4CF2D6FF1A2874590080B019 /* Supporting Files */ = { isa = PBXGroup; children = ( 4CF2D7001A2874590080B019 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; A5F13419D3ADD74DF689E684 /* Pods */ = { isa = PBXGroup; children = ( 0BCB7CE7308CCE271DCE5AFE /* Pods.debug.xcconfig */, 2BBB8199B14BBE8D0114A5B4 /* Pods.release.xcconfig */, ); name = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 4CF2D6E11A2874590080B019 /* FakeZhihuDaily */ = { isa = PBXNativeTarget; buildConfigurationList = 4CF2D7051A2874590080B019 /* Build configuration list for PBXNativeTarget "FakeZhihuDaily" */; buildPhases = ( 13A4D9FFDE2A9E16F9275EC3 /* Check Pods Manifest.lock */, 4CF2D6DE1A2874590080B019 /* Sources */, 4CF2D6DF1A2874590080B019 /* Frameworks */, 4CF2D6E01A2874590080B019 /* Resources */, 8FDFDC040964DDCED39B59CE /* Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = FakeZhihuDaily; productName = FakeZhihuDaily; productReference = 4CF2D6E21A2874590080B019 /* FakeZhihuDaily.app */; productType = "com.apple.product-type.application"; }; 4CF2D6FA1A2874590080B019 /* FakeZhihuDailyTests */ = { isa = PBXNativeTarget; buildConfigurationList = 4CF2D7081A2874590080B019 /* Build configuration list for PBXNativeTarget "FakeZhihuDailyTests" */; buildPhases = ( 4CF2D6F71A2874590080B019 /* Sources */, 4CF2D6F81A2874590080B019 /* Frameworks */, 4CF2D6F91A2874590080B019 /* Resources */, ); buildRules = ( ); dependencies = ( 4CF2D6FD1A2874590080B019 /* PBXTargetDependency */, ); name = FakeZhihuDailyTests; productName = FakeZhihuDailyTests; productReference = 4CF2D6FB1A2874590080B019 /* FakeZhihuDailyTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 4CF2D6DA1A2874590080B019 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0610; ORGANIZATIONNAME = gnou; TargetAttributes = { 4CF2D6E11A2874590080B019 = { CreatedOnToolsVersion = 6.1; }; 4CF2D6FA1A2874590080B019 = { CreatedOnToolsVersion = 6.1; TestTargetID = 4CF2D6E11A2874590080B019; }; }; }; buildConfigurationList = 4CF2D6DD1A2874590080B019 /* Build configuration list for PBXProject "FakeZhihuDaily" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 4CF2D6D91A2874590080B019; productRefGroup = 4CF2D6E31A2874590080B019 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 4CF2D6E11A2874590080B019 /* FakeZhihuDaily */, 4CF2D6FA1A2874590080B019 /* FakeZhihuDailyTests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 4CF2D6E01A2874590080B019 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 4CF2D6F11A2874590080B019 /* Main.storyboard in Resources */, 4C2144071A39A72200757A36 /* Localizable.strings in Resources */, 4CF2D6F61A2874590080B019 /* LaunchScreen.xib in Resources */, 4CF2D6F31A2874590080B019 /* Images.xcassets in Resources */, 4CB9CE811A5BD493001D4A3A /* ContentHeaderView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 4CF2D6F91A2874590080B019 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 13A4D9FFDE2A9E16F9275EC3 /* Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Check Pods Manifest.lock"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; showEnvVarsInLog = 0; }; 8FDFDC040964DDCED39B59CE /* Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Copy Pods Resources"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 4CF2D6DE1A2874590080B019 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 4C87F4D91A32EED6008A8555 /* AppDelegate+MOC.m in Sources */, 4C9C8F021A400568009AE2F9 /* ThemeStory+Create.m in Sources */, 4C813F171A3D8BE60033D81C /* Theme+Create.m in Sources */, 4CF59B681A37EC3200475CB7 /* Date+Create.m in Sources */, 4C9C8EFF1A3FE206009AE2F9 /* NetworkClient.m in Sources */, 4C9C8EF61A3FD467009AE2F9 /* Theme.m in Sources */, 4CBD5DFA1A3AF777001C6FC0 /* SideBarTableViewController.m in Sources */, 4C87F4E61A32FE64008A8555 /* MainStoriesViewController.m in Sources */, 4CF2D6EB1A2874590080B019 /* AppDelegate.m in Sources */, 4CB9CE841A5BD765001D4A3A /* ContentHeaderView.m in Sources */, 4C9C8F051A40114F009AE2F9 /* ThemeStoriesViewController.m in Sources */, 4CF59B651A37EB3400475CB7 /* Story.m in Sources */, 4CF59B6B1A37ED3100475CB7 /* Date.m in Sources */, 4CF2D71F1A288B610080B019 /* FakeZhihuDaily.xcdatamodeld in Sources */, 4C43BB8B1A5FA50F00371E89 /* StoriesList.swift in Sources */, 4C9C8EF31A3FD450009AE2F9 /* ThemeStory.m in Sources */, 4CF2D6E81A2874590080B019 /* main.m in Sources */, 4C32328D1A5BAD8200D63136 /* ContentViewController.m in Sources */, 4C5E0E441A42DB3D00E7934F /* ThemeBodyViewController.m in Sources */, 186896731A738D1D005EEDA7 /* TitleCell.m in Sources */, 4C87F4DD1A32F131008A8555 /* Story+Create.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 4CF2D6F71A2874590080B019 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 4CF2D7021A2874590080B019 /* FakeZhihuDailyTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 4CF2D6FD1A2874590080B019 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4CF2D6E11A2874590080B019 /* FakeZhihuDaily */; targetProxy = 4CF2D6FC1A2874590080B019 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 4CF2D6EF1A2874590080B019 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 4CF2D6F01A2874590080B019 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 4CF2D6F41A2874590080B019 /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( 4CF2D6F51A2874590080B019 /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 4CF2D7031A2874590080B019 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; name = Debug; }; 4CF2D7041A2874590080B019 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; name = Release; }; 4CF2D7061A2874590080B019 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 0BCB7CE7308CCE271DCE5AFE /* Pods.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = FakeZhihuDaily/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "FakeZhihuDaily/FakeZhihuDaily-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 4CF2D7071A2874590080B019 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 2BBB8199B14BBE8D0114A5B4 /* Pods.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; INFOPLIST_FILE = FakeZhihuDaily/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "FakeZhihuDaily/FakeZhihuDaily-Bridging-Header.h"; }; name = Release; }; 4CF2D7091A2874590080B019 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = FakeZhihuDailyTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FakeZhihuDaily.app/FakeZhihuDaily"; }; name = Debug; }; 4CF2D70A1A2874590080B019 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", ); INFOPLIST_FILE = FakeZhihuDailyTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/FakeZhihuDaily.app/FakeZhihuDaily"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 4CF2D6DD1A2874590080B019 /* Build configuration list for PBXProject "FakeZhihuDaily" */ = { isa = XCConfigurationList; buildConfigurations = ( 4CF2D7031A2874590080B019 /* Debug */, 4CF2D7041A2874590080B019 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4CF2D7051A2874590080B019 /* Build configuration list for PBXNativeTarget "FakeZhihuDaily" */ = { isa = XCConfigurationList; buildConfigurations = ( 4CF2D7061A2874590080B019 /* Debug */, 4CF2D7071A2874590080B019 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4CF2D7081A2874590080B019 /* Build configuration list for PBXNativeTarget "FakeZhihuDailyTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 4CF2D7091A2874590080B019 /* Debug */, 4CF2D70A1A2874590080B019 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCVersionGroup section */ 4CF2D71D1A288B610080B019 /* FakeZhihuDaily.xcdatamodeld */ = { isa = XCVersionGroup; children = ( 4CF2D71E1A288B610080B019 /* FakeZhihuDaily.xcdatamodel */, ); currentVersion = 4CF2D71E1A288B610080B019 /* FakeZhihuDaily.xcdatamodel */; path = FakeZhihuDaily.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; }; /* End XCVersionGroup section */ }; rootObject = 4CF2D6DA1A2874590080B019 /* Project object */; } ================================================ FILE: FakeZhihuDaily.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: FakeZhihuDaily.xcodeproj/xcuserdata/mc.xcuserdatad/xcschemes/FakeZhihuDaily.xcscheme ================================================ ================================================ FILE: FakeZhihuDaily.xcodeproj/xcuserdata/mc.xcuserdatad/xcschemes/xcschememanagement.plist ================================================ SchemeUserState FakeZhihuDaily.xcscheme orderHint 0 SuppressBuildableAutocreation 4CF2D6E11A2874590080B019 primary 4CF2D6FA1A2874590080B019 primary ================================================ FILE: FakeZhihuDaily.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: FakeZhihuDaily.xcworkspace/xcuserdata/mc.xcuserdatad/WorkspaceSettings.xcsettings ================================================ HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges SnapshotAutomaticallyBeforeSignificantChanges ================================================ FILE: FakeZhihuDaily.xcworkspace/xcuserdata/mc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist ================================================ ================================================ FILE: FakeZhihuDailyTests/FakeZhihuDailyTests.m ================================================ // // FakeZhihuDailyTests.m // FakeZhihuDailyTests // // Created by CuiMingyu on 14/11/28. // Copyright (c) 2014年 gnou. All rights reserved. // #import #import @interface FakeZhihuDailyTests : XCTestCase @end @implementation FakeZhihuDailyTests - (void)setUp { [super setUp]; // Put setup code here. This method is called before the invocation of each test method in the class. } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } - (void)testExample { // This is an example of a functional test case. XCTAssert(YES, @"Pass"); } - (void)testPerformanceExample { // This is an example of a performance test case. [self measureBlock:^{ // Put the code you want to measure the time of here. }]; } @end ================================================ FILE: FakeZhihuDailyTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier com.gnou.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: Podfile ================================================ source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.1' pod 'AFNetworking' pod 'Mantle' pod 'TSMessages' pod 'ReactiveCocoa' pod 'SDWebImage' pod 'SWRevealViewController' ================================================ FILE: README.md ================================================ :warning: THIS PROJECT IS NO LONGER BEING ACTIVELY MAINTAINED. :warning: 此项目已停止开发。 仿知乎日报iOS客户端,api来自于[知乎日报API分析](https://github.com/izzyleung/ZhihuDailyPurify/wiki/%E7%9F%A5%E4%B9%8E%E6%97%A5%E6%8A%A5-API-%E5%88%86%E6%9E%90) ### How to use 1. Make sure you have [**CocoaPods**](http://cocoapods.org/) installed 2. `pod install` 3. open *FakeZhihuDaily.xcworkspace*, build & run 4. If you have any questions, feel free to contact me [Mingyu Cui](mailto:malvin.cui@gmail.com) ### Screenshot #### 主页 ![Home Page](https://raw.githubusercontent.com/gnou/FakeZhihuDaily/master/Screenshot/Home.png) #### 内容页 ![Content Page](https://raw.githubusercontent.com/gnou/FakeZhihuDaily/master/Screenshot/ContentPage.png) #### 主题日报列表 ![Theme List](https://raw.githubusercontent.com/gnou/FakeZhihuDaily/master/Screenshot/ThemeList.png) #### 主题日报 ![Theme](https://raw.githubusercontent.com/gnou/FakeZhihuDaily/master/Screenshot/Theme.png)