Last active
December 17, 2015 00:48
-
-
Save ifournight/5523255 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
// Relative path for library's info.plist. | |
UIKIT_EXTERN NSString *kLibraryInfoPlistPath; | |
// Relative path for library's NSManagedObjectStore. | |
UIKIT_EXTERN NSString *kLibraryStorePath; | |
// Relative path where all library's documents locate. | |
UIKIT_EXTERN NSString *kLibraryDocumentPath; | |
// SLibrary represents one Apple documentation library. | |
// Each Apple documentation library file locate in App's Document directory. | |
// And it's SLibraryManager's responsibility to locate them and add their's Core Data information. | |
@interface SLibrary : NSObject | |
// Absolute path in App's Document directory. | |
@property (nonatomic, copy) NSString *path; | |
// Library's name. | |
@property (nonatomic, copy) NSString *name; | |
// Copyright. | |
@property (nonatomic, copy) NSString *copyright; | |
// ID. | |
@property (nonatomic, copy) NSString *ID; | |
// Fallback. | |
@property (nonatomic, copy) NSString *fallback; | |
// Library's NSManagedObjectStore's URL that located inside library. | |
@property (nonatomic, strong) NSURL *storeURL; | |
// Root SNodes in this library. Will fetched lazily. | |
@property (nonatomic, strong) NSArray *rootNodes; | |
// Desiganted Initializer. | |
- (id)initWithPath:(NSString *)path; | |
@end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "SLibrary.h" | |
const NSString *kLibraryInfoPlistPath = @"Contents/Info.plist"; | |
const NSString *kLibraryStorePath = @"Contents/Resources/docSet.dsidx"; | |
const NSString *kLibraryDocumentPath @"Contents/Resources/Documents"; | |
@implementation SLibrary | |
- (id)initWithPath:(NSString *)path | |
{ | |
self = [super init]; | |
if (self) { | |
_path = path; | |
NSString *infoPlistPath = [path stringByAppendingPathComponent:kLibraryInfoPlistPath]; | |
NSDictionary *infoPlist = [NSDictionary dictionaryWithContentsOfFile:infoPlistPath]; | |
if (infoPlist) { | |
_name = infoPlist[@"CFBundleName"]; | |
_copyright = infoPlist[@"NSHumanReadableCopyright"]; | |
_ID = infoPlist[@"CFBundleIdentifier"]; | |
_fallback = infoPlist[@"DocSetFallbackURL"]; | |
NSString *storePath = [_path stringByAppendingPathComponent:kLibraryStorePath]; | |
_storeURL = [NSURL fileURLWithPath:storePath]; | |
} else { | |
NSLog(@"Library: fail to init because of nil info.plist"); | |
} | |
} | |
return self; | |
} | |
- (NSArray *)rootNodes | |
{ | |
if (_rootNodes == nil) { | |
// Create NSManagedObjectContext. | |
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; | |
context.persistentStoreCoordinator = [[SLibraryManager share] persistentStoreCoordinator]; | |
// ObjectIDDescription | |
NSExpressionDescription *objectIDDescription = [[NSExpressionDescription alloc] init]; | |
objectIDDescription.name = @"Object ID"; | |
objectIDDescription.expression = [NSExpression expressionForEvaluatedObject]; | |
objectIDDescription.expressionResultType = NSObjectIDAttributeType; | |
// Fetch request and request properties. | |
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequstWithEntityName:@"Node"]; | |
// Predicate | |
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"kIsSearchable == NO AND primaryParent.kName == [c] %@", @"Developer Library"]; | |
// SortDescriptors | |
fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithName:@"kName" ascending:YES selector:@selector(caseInsensitiveCompare:)]]; | |
// Affected Stores | |
fetchRequest.affectedStores = @[[[[SLibraryManager share] coordinator] persistentStoreForURL:self.storeURL]]; | |
// Result type. | |
fetchRequest.resultType = NSDictionaryResultType. | |
// Properties to fetch. | |
NSEntityDescription *nodeEntity = [NSEntityDescription entityForName:@"Node" inManagedObjectContext:context]; | |
NSAttributeDescription *nodeNameAttribute = [nodeEntity attributesByName][@"kName"]; | |
fetchRequest.propertiesToFetch = @[objectIDDescription, nodeNameAttribute]; | |
NSArray *fetchResults = [context executeFetchRequest:fetchRequest error:nil]; | |
// Turn fetch result into SNodes. | |
NSMutableArray *rootNodes = [[NSMutableArray alloc] init]; | |
for (NSDictionary *fetchResults in fetchResults] { | |
SNodes *node = [[SNode alloc] initWithName:fetchResult[@"kName"] ID:fetchResult[@"objectID"]]; | |
[rootNodes addObject:node]; | |
} | |
_rootNodes = rootNodes; | |
} | |
return _rootNodes; | |
} | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <CoreData/CoreData.h> | |
#import "SLibrary.h" | |
UIKIT_EXTERN NSString *SLibraryManagerWillReloadLibrariesNotification; | |
UIKIT_EXTERN NSString *SLibraryManagerDidReloadLibrariesNottification; | |
// SLibraryManager is a singleton object, use share to get it. | |
// It is responsible for Manage all the libraries in App's Document directory, reload when necessary. | |
// And each reload libraries, library manager will load all libraries' Core Data stuff appropriately, | |
// for other class that that need to fetch something from Core Data, like SSearchLibrary's search job; Library's root nodes; SNode, SToken fetch information properties. | |
@interface SLibraryManager : NSObject | |
// Managed libraries. | |
@property (nonatomic, strong) NSArray *libraries; | |
// An dictionary which each library object's key is library's corresponding managed object store's ID. | |
// This property's purpose: | |
// Because NSManagedObject like token and node, don't have a property or method that can fetch its corresponding NSManagedObjectStore, and Project needs to get object's store to compose object's URL. | |
// But NSManagedObject can fetch its storeID, so this property can help SToken and SNode to get its mother library. | |
@property (nonatomic, strong) NSDictionary *librariesByStoreID; | |
// NSPersistentStoreCoordinator that holds all libraries' store within itself. | |
// The one and only coordinator throughout the application. | |
@property (nonatomic, strong) NSPersistentStoreCoordinator *coordinator; | |
// Use this method to get the singleton manager. | |
+ (id)share; | |
// Reload libraries. | |
- (void)reloadLibraries; | |
@end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "SLibraryManager.h" | |
const NSString *SLibraryManagerWillReloadLibrariesNotification = @"Library Manager Will Reload Libraries"; | |
const NSString *SLibraryManagerDidReloadLibrariesNotification = @Library Manager Did Reload Libraries"; | |
@interface SLibraryManager() | |
// Use SLibrary's rootNodes property to prefetch all libraries' root nodes. | |
- (void)prefetchLibrariesRootNodes; | |
@end | |
@implementation SLibraryManager | |
- (id)init | |
{ | |
self = [super init]; | |
if (self) { | |
// NSManagedObjectModel | |
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"docSet" withExtension:@"mom"]; | |
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; | |
// NSPersistentStoreCoordinator. | |
_coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; | |
} | |
return self; | |
} | |
+ (id)share | |
{ | |
static SLibraryManager *share = nil; | |
dispatch_once_t = onceToken; | |
dispatch_once(&onceToken, ^{ | |
share = [[SLibraryManager alloc] init]; | |
}); | |
return share; | |
} | |
- (void)reloadLibraries | |
{ | |
// Remove old store in coordinator. | |
if (self.coordinator.persistentStores) { | |
for (NSPersistentStore *store in self.coordinator.persistentStores) { | |
[self.coordinator removePersistentStore:store error:nil]; | |
} | |
} | |
// Scan and locate files with docset extension in App's Document directory. | |
NSMutableArray *libraries = [NSMutableArray alloc] init]; | |
NSMutableDictionary *librariesByStoreID = [NSMutableDictionary alloc] init]; | |
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; | |
NSFileManager *fileManager = [NSFileManager defaultManager]; | |
for (NSString *path in [fileManager contentsOfDirectoryAtPath:documentPath error:nil]) { | |
if ([path.pathExtension isEqualToString:@"docset"]) { | |
NSString *libraryPath = [documentPath stringByAppendingPathComponent:path]; | |
Library *library = [[Library alloc] initWithPath:libraryPath]; | |
// Add persistent store into coordinator. | |
[self.coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:library.storeURL options:@{NSReadOnlyPersistentStoreOption : @YES} error:nil]; | |
NSPersistentStore *store = [self.coordinator persistentStoreForURL:library.storeURL]; | |
[libraries addObject:library]; | |
[librariesByStoreID setObject:library forKey:store.identifier]; | |
} | |
} | |
self.libraries = libraries; | |
self.librariesByStoreID = librariesByStoreID; | |
// Every time reload libraries, prefetch libraries' root nodes. | |
[self prefetchLibrariesRootNodes]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment