├── .gitignore ├── .idea ├── .name ├── CoreDataEnvir.iml ├── encodings.xml ├── misc.xml ├── modules.xml ├── scopes │ └── scope_settings.xml ├── vcs.xml ├── workspace.xml └── xcode.xml ├── .travis.yml ├── CoreDataEnvir.podspec ├── CoreDataEnvir ├── CoreDataEnvirHeader.h └── Info.plist ├── CoreDataEnvirSample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── CoreDataEnvirSample.xccheckout │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── CoreDataEnvir.xcscheme │ └── CoreDataEnvirSampleTests.xcscheme ├── CoreDataEnvirSample.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── CoreDataEnvirSample ├── AppDelegate.h ├── AppDelegate.m ├── ConcurrencyViewController.h ├── ConcurrencyViewController.m ├── CoreDataEnvirSample-Bridging-Header.h ├── RelationshipViewController.h ├── RelationshipViewController.m ├── Supporting Files │ ├── CoreDataEnvirSample-Info.plist │ ├── CoreDataEnvirSample-Prefix.pch │ ├── Default-568h@2x.png │ ├── Default.png │ ├── Default@2x.png │ ├── Member.h │ ├── Member.m │ ├── SampleModel.xcdatamodeld │ │ └── SampleModel.xcdatamodel │ │ │ └── contents │ ├── Team.h │ ├── Team.m │ ├── demo.plist │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── SwiftViewController.swift ├── ViewController.h ├── ViewController.m └── zh-Hans.lproj │ └── InfoPlist.strings ├── CoreDataEnvirSampleTests ├── CoreDataEnvirTests.m └── Supporting Files │ ├── CoreDataEnvirSampleTests-Info.plist │ ├── en.lproj │ └── InfoPlist.strings │ └── zh-Hans.lproj │ └── InfoPlist.strings ├── CoreDataEnvirTests ├── CoreDataEnvirTests.m └── Info.plist ├── LICENSE ├── Member+CoreDataClass.swift ├── Member+CoreDataProperties.swift ├── ObjcUML ├── Scripts │ ├── d3.v3.js │ ├── d3.v3.min.js │ ├── d3js-LICENSE │ └── parse.js ├── dependency.css ├── index.html └── origin.js ├── Podfile ├── Podfile.lock ├── Pods ├── Local Podspecs │ └── CoreDataEnvir.podspec.json ├── Manifest.lock ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── dehengxu.xcuserdatad │ │ └── xcschemes │ │ ├── CoreDataEnvir.xcscheme │ │ ├── Pods-CoreDataEnvirSample.xcscheme │ │ ├── Pods-CoreDataEnvirSampleTests.xcscheme │ │ └── xcschememanagement.plist └── Target Support Files │ ├── CoreDataEnvir │ ├── CoreDataEnvir-Info.plist │ ├── CoreDataEnvir-dummy.m │ ├── CoreDataEnvir-prefix.pch │ ├── CoreDataEnvir-umbrella.h │ ├── CoreDataEnvir.debug.xcconfig │ ├── CoreDataEnvir.modulemap │ └── CoreDataEnvir.release.xcconfig │ ├── Pods-CoreDataEnvirSample │ ├── Pods-CoreDataEnvirSample-Info.plist │ ├── Pods-CoreDataEnvirSample-acknowledgements.markdown │ ├── Pods-CoreDataEnvirSample-acknowledgements.plist │ ├── Pods-CoreDataEnvirSample-dummy.m │ ├── Pods-CoreDataEnvirSample-frameworks-Debug-input-files.xcfilelist │ ├── Pods-CoreDataEnvirSample-frameworks-Debug-output-files.xcfilelist │ ├── Pods-CoreDataEnvirSample-frameworks-Release-input-files.xcfilelist │ ├── Pods-CoreDataEnvirSample-frameworks-Release-output-files.xcfilelist │ ├── Pods-CoreDataEnvirSample-frameworks.sh │ ├── Pods-CoreDataEnvirSample-umbrella.h │ ├── Pods-CoreDataEnvirSample.debug.xcconfig │ ├── Pods-CoreDataEnvirSample.modulemap │ └── Pods-CoreDataEnvirSample.release.xcconfig │ └── Pods-CoreDataEnvirSampleTests │ ├── Pods-CoreDataEnvirSampleTests-Info.plist │ ├── Pods-CoreDataEnvirSampleTests-acknowledgements.markdown │ ├── Pods-CoreDataEnvirSampleTests-acknowledgements.plist │ ├── Pods-CoreDataEnvirSampleTests-dummy.m │ ├── Pods-CoreDataEnvirSampleTests-umbrella.h │ ├── Pods-CoreDataEnvirSampleTests.debug.xcconfig │ ├── Pods-CoreDataEnvirSampleTests.modulemap │ └── Pods-CoreDataEnvirSampleTests.release.xcconfig ├── README.md ├── README_zh.md ├── Team+CoreDataClass.swift ├── Team+CoreDataProperties.swift ├── backup.sh ├── build.sh ├── check ├── podupdate.sh ├── push2pods ├── pushtag ├── src └── CoreDataEnvir │ ├── CoreDataEnvir.h │ ├── CoreDataEnvir.m │ ├── CoreDataEnvirDescriptor.h │ ├── CoreDataEnvirDescriptor.m │ ├── CoreDataEnvirHeader.h │ ├── CoreDataEnvirObserver.h │ ├── CoreDataEnvir_Background.h │ ├── CoreDataEnvir_Background.m │ ├── CoreDataEnvir_Main.h │ ├── CoreDataEnvir_Main.m │ ├── CoreDataRescureDelegate.h │ ├── ManagedObject │ ├── NSManagedObject_Background.h │ ├── NSManagedObject_Background.m │ ├── NSManagedObject_Convenient.h │ ├── NSManagedObject_Convenient.m │ ├── NSManagedObject_MainThread.h │ └── NSManagedObject_MainThread.m │ └── Private │ ├── CoreDataEnvir_Private.h │ └── CoreDataEnvir_Private.m └── syncgit /.gitignore: -------------------------------------------------------------------------------- 1 | ObjcUML/ 2 | xcuserdata/ 3 | build/ 4 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | CoreDataEnvirSample -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/xcode.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode6.4 2 | language: objective-c 3 | xcode_project: CoreDataEnvirSample.xcodeproj 4 | xcode_scheme: CoreDataEnvirSampleTests 5 | -------------------------------------------------------------------------------- /CoreDataEnvir.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint CoreDataEnvir.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "CoreDataEnvir" 19 | s.version = "0.13.0-beta.1" 20 | s.summary = "CoreDataEnvir is a CoreData wrapper which use CoreData in convient way and supply thread safe in concurrenct programming." 21 | 22 | s.description = <<-DESC 23 | CoreDataEnvir is a CoreData wrapper which use CoreData in convient way and supply thread safe in concurrenct programming. You can use it concurrenctly,run seperate CoreDataEnvir instance on one thread. 24 | DESC 25 | 26 | s.homepage = "https://dehengxu.github.io/CoreDataEnvir" 27 | # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" 28 | s.module_name = "CoreDataEnvir" 29 | 30 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 31 | # 32 | # Licensing your code is important. See http://choosealicense.com for more info. 33 | # CocoaPods will detect a license file if there is a named LICENSE* 34 | # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. 35 | # 36 | 37 | s.license = "MIT" 38 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" } 39 | 40 | 41 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 42 | # 43 | # Specify the authors of the library, with email addresses. Email addresses 44 | # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also 45 | # accepts just a name if you'd rather not provide an email address. 46 | # 47 | # Specify a social_media_url where others can refer to, for example a twitter 48 | # profile URL. 49 | # 50 | 51 | s.author = { "DehengXu" => "dehengxu@outlook.com" } 52 | # Or just: s.author = "CyberLion" 53 | # s.authors = { "CyberLion" => "dehengxu@outlook.com" } 54 | s.social_media_url = "https://github.com/dehengxu" 55 | 56 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 57 | # 58 | # If this Pod runs only on iOS or OS X, then specify the platform and 59 | # the deployment target. You can optionally include the target after the platform. 60 | # 61 | 62 | s.platform = :ios, '10.0' 63 | # s.platform = :ios, "5.0" 64 | 65 | # When using multiple platforms 66 | # s.ios.deployment_target = "5.0" 67 | # s.osx.deployment_target = "10.7" 68 | 69 | 70 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 71 | # 72 | # Specify the location from where the source should be retrieved. 73 | # Supports git, hg, bzr, svn and HTTP. 74 | # 75 | 76 | s.source = { :git => "https://github.com/dehengxu/CoreDataEnvir.git", :tag => s.version } 77 | 78 | 79 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 80 | # 81 | # CocoaPods is smart about how it includes source code. For source files 82 | # giving a folder will include any h, m, mm, c & cpp files. For header 83 | # files it will include any header in the folder. 84 | # Not including the public_header_files will make all headers public. 85 | # 86 | 87 | s.source_files = "src/CoreDataEnvir/*.h", "src/CoreDataEnvir/**/*.{h,m}" 88 | # s.exclude_files = "CoreDataEnvir/Debug" 89 | 90 | s.public_header_files = "src/CoreDataEnvir/**/*.h" #, "src/CoreDataEnvir/*.h" 91 | 92 | 93 | # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 94 | # 95 | # A list of resources included with the Pod. These are copied into the 96 | # target bundle with a build phase script. Anything else will be cleaned. 97 | # You can preserve files from being cleaned, please don't preserve 98 | # non-essential files like tests, examples and documentation. 99 | # 100 | 101 | # s.resource = "icon.png" 102 | # s.resources = "Resources/*.png" 103 | 104 | # s.preserve_paths = "FilesToSave", "MoreFilesToSave" 105 | 106 | 107 | # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 108 | # 109 | # Link your library with frameworks, or libraries. Libraries do not include 110 | # the lib prefix of their name. 111 | # 112 | 113 | # s.framework = "CoreData" 114 | s.frameworks = "CoreData"#, "AnotherFramework" 115 | 116 | # s.library = "iconv" 117 | # s.libraries = "iconv", "xml2" 118 | 119 | 120 | # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 121 | # 122 | # If your library depends on compiler flags you can set them in the xcconfig hash 123 | # where they will only apply to your library. If you depend on other Podspecs 124 | # you can include multiple dependencies to ensure it works. 125 | 126 | s.requires_arc = true 127 | s.info_plist = { 128 | "CFBundleIdentifier"=>"com.dehengxu.CoreDataEnvir" 129 | } 130 | # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 131 | # s.dependency "JSONKit", "~> 1.4" 132 | 133 | end 134 | -------------------------------------------------------------------------------- /CoreDataEnvir/CoreDataEnvirHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvirHeader.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | //#ifndef CoreDataEnvirSample_CoreDataEnvirHeader_h 10 | //#define CoreDataEnvirSample_CoreDataEnvirHeader_h 11 | 12 | #import "CoreDataEnvir.h" 13 | #import "CoreDataEnvir_Main.h" 14 | #import "CoreDataEnvir_Background.h" 15 | 16 | #import "NSManagedObject_Convenient.h" 17 | #import "NSManagedObject_MainThread.h" 18 | #import "NSManagedObject_Background.h" 19 | #if __has_include("NSObject_Debug.h") 20 | #import "NSObject_Debug.h" 21 | #endif 22 | 23 | //! Project version number for CoreDataEnvir. 24 | FOUNDATION_EXPORT double CoreDataEnvirVersionNumber; 25 | 26 | //! Project version string for CoreDataEnvir. 27 | FOUNDATION_EXPORT const unsigned char CoreDataEnvirVersionString[]; 28 | 29 | //#endif 30 | -------------------------------------------------------------------------------- /CoreDataEnvir/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /CoreDataEnvirSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CoreDataEnvirSample.xcodeproj/project.xcworkspace/xcshareddata/CoreDataEnvirSample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 6B39E785-E4A3-4D88-944D-A0CB7355FC94 9 | IDESourceControlProjectName 10 | CoreDataEnvirSample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 0625EBF42F455C9F64085466B99E788FF87C770A 14 | bitbucket.org:xudeheng/CoreDataEnvir.git 15 | 16 | IDESourceControlProjectPath 17 | CoreDataEnvirSample.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 0625EBF42F455C9F64085466B99E788FF87C770A 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | bitbucket.org:xudeheng/CoreDataEnvir.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 0625EBF42F455C9F64085466B99E788FF87C770A 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 0625EBF42F455C9F64085466B99E788FF87C770A 36 | IDESourceControlWCCName 37 | CoreDataEnvir 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CoreDataEnvirSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CoreDataEnvirSample.xcodeproj/xcshareddata/xcschemes/CoreDataEnvir.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /CoreDataEnvirSample.xcodeproj/xcshareddata/xcschemes/CoreDataEnvirSampleTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 37 | 38 | 44 | 45 | 47 | 48 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /CoreDataEnvirSample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 18 | 19 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CoreDataEnvirSample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-4-7. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ViewController; 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @property (strong, nonatomic) ViewController *viewController; 18 | @property (strong, nonatomic) UINavigationController *navigationController; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-4-7. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | #import "ViewController.h" 12 | 13 | #import "CoreDataEnvir.h" 14 | #import "Team.h" 15 | #import "Member.h" 16 | #import 17 | 18 | _Bool checkEnv(const char* name) { 19 | const char* env = getenv(name); 20 | return (env != 0 && strcmp(env, "1") == 0); 21 | } 22 | 23 | @implementation AppDelegate 24 | 25 | - (void)dealloc 26 | { 27 | } 28 | 29 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 30 | { 31 | if (!checkEnv("debug")) { 32 | exit(0); 33 | } 34 | if (!checkEnv("demo")) { 35 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 36 | self.window.rootViewController = [UIViewController new]; 37 | self.window.rootViewController.view.backgroundColor = UIColor.blackColor; 38 | [self.window makeKeyAndVisible]; 39 | #if true // test legacy 40 | // [CoreDataEnvir.backgroundInstance asyncWithBlock:^(CoreDataEnvir * _Nonnull db) { 41 | // [Team insertItemInContext:db fillData:^(Team* _Nonnull item) { 42 | // item.name = @"CybLion"; 43 | // }]; 44 | // [db saveDataBase]; 45 | // }]; 46 | 47 | // [Team insertItemOnBackgroundWithFillingBlock:^(Team* _Nonnull item) { 48 | // item.name = @"Lion"; 49 | // }]; 50 | 51 | // [Team insertItemWithFillingBlock:^(Team* item) { 52 | // item.name = @"Lion"; 53 | // [item save]; 54 | // }]; 55 | 56 | CoreDataEnvir* db = [CoreDataEnvirDescriptor.defaultInstance backgroundInstance]; 57 | [Team insertItemInContext:db]; 58 | [db saveDataBase]; 59 | printf("Team total count: %lu\n", Team.totalCount); 60 | #else 61 | NSURL* modelURL = [NSBundle.mainBundle URLForResource:@"SampleModel" withExtension:@"momd"]; 62 | CoreDataEnvirBlock initBlock = ^(CoreDataEnvir* db) { 63 | [db setupModelWithURL:modelURL]; 64 | 65 | NSString* searchedPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true) lastObject]; 66 | NSLog(@"search path: %@", searchedPath); 67 | NSURL* dbURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/db.sqlite", searchedPath]]; 68 | NSLog(@"dbURL: %@", dbURL); 69 | if (dbURL) { 70 | [db setupDefaultPersistentStoreWithURL:dbURL]; 71 | } 72 | }; 73 | CoreDataEnvir* db = [CoreDataEnvir create]; 74 | [db setupWithBlock:initBlock]; 75 | CoreDataEnvir* db2 = [CoreDataEnvir create]; 76 | [db2 setupWithBlock:initBlock]; 77 | 78 | [db syncInBlock:^(CoreDataEnvir * _Nonnull db) { 79 | Team* obj = [Team insertItemInContext:db]; 80 | obj.name = @"new pattern"; 81 | [db saveDataBase]; 82 | 83 | NSFetchRequest* req = [Team newFetchRequestInContext:db]; 84 | NSError* err = nil; 85 | NSUInteger count = [db.context countForFetchRequest:req error:&err]; 86 | printf("Team total count: %lu\n", count); 87 | }]; 88 | 89 | #endif 90 | return true; 91 | } 92 | NSLog(@"CoreDataEnvirVersionString: %s", CoreDataEnvirVersionString); 93 | NSLog(@"CoreDataEnvirVersionNumber: %f", CoreDataEnvirVersionNumber); 94 | //Set db file name and model file name. 95 | // [CoreDataEnvir registerDefaultDataFileName:@"db.sqlite"]; 96 | // [CoreDataEnvir registerDefaultModelFileName:@"SampleModel"]; 97 | 98 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 99 | // Override point for customization after application launch. 100 | self.viewController = [[ViewController alloc] initWithNibName:nil bundle:nil]; 101 | self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 102 | 103 | //NSLog(@"ver: %f", CoreDataEnvirVersionNumber); 104 | 105 | self.window.rootViewController = self.navigationController; 106 | [self.window makeKeyAndVisible]; 107 | 108 | return YES; 109 | } 110 | 111 | - (void)applicationWillResignActive:(UIApplication *)application 112 | { 113 | // 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. 114 | // 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. 115 | } 116 | 117 | - (void)applicationDidEnterBackground:(UIApplication *)application 118 | { 119 | // 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. 120 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 121 | } 122 | 123 | - (void)applicationWillEnterForeground:(UIApplication *)application 124 | { 125 | // 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. 126 | } 127 | 128 | - (void)applicationDidBecomeActive:(UIApplication *)application 129 | { 130 | // 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. 131 | } 132 | 133 | - (void)applicationWillTerminate:(UIApplication *)application 134 | { 135 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 136 | } 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/ConcurrencyViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ConcurrencyViewController.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CoreDataEnvir.h" 11 | #import "CoreDataEnvirHeader.h" 12 | 13 | @class Team; 14 | @class Member; 15 | 16 | @interface ConcurrencyViewController : UIViewController 17 | < 18 | CoreDataRescureDelegate 19 | > 20 | { 21 | dispatch_semaphore_t __runs_sema; 22 | } 23 | 24 | @property (nonatomic, strong) Team *teamOnMainThread; 25 | @property (nonatomic, strong) Team *teamOnBackground; 26 | 27 | - (IBAction)onClick_test:(id)sender; 28 | - (IBAction)onClick_clearAll:(id)sender; 29 | - (IBAction)onClick_look:(id)sender; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/ConcurrencyViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ConcurrencyViewController.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "ConcurrencyViewController.h" 10 | 11 | #import 12 | #import 13 | 14 | //#import 15 | @import CoreDataEnvir; 16 | #import "Team.h" 17 | #import "Member.h" 18 | 19 | #define THREAD_NUMBER 1 20 | #define LOOP_NUMBER_PER_THREAD 1024 * 2 21 | 22 | //Test concurrency. 23 | #define TESTING_A 1 24 | 25 | #define TESTING_B 2 26 | //Test creating mutch number of instance. 27 | #define TESTING_C 3 28 | //Test IO stream. 29 | #define TESTING_D 4 30 | 31 | #define testing_case TESTING_A 32 | 33 | @interface ConcurrencyViewController () 34 | 35 | @end 36 | 37 | @implementation ConcurrencyViewController 38 | 39 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 40 | { 41 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 42 | if (self) { 43 | // Custom initialization 44 | __runs_sema = dispatch_semaphore_create(1l); 45 | } 46 | return self; 47 | } 48 | 49 | - (void)dealloc 50 | { 51 | } 52 | 53 | - (void)viewDidLoad 54 | { 55 | [super viewDidLoad]; 56 | // Do any additional setup after loading the view. 57 | self.view.backgroundColor = [UIColor lightGrayColor]; 58 | 59 | NSString * actions[3] = {@"onClick_test:", @"onClick_clearAll:", @"onClick_look:"}; 60 | NSString * titles[3] = {@"Test Concurrency", @"Clear DB", @"Watch"}; 61 | 62 | CGSize buttonSize = CGSizeMake(180, 60); 63 | 64 | for (int i = 0; i < 3; i++) { 65 | 66 | UIButton *btn = [[UIButton alloc] initWithFrame:CGRectZero]; 67 | btn.frame = CGRectMake(20, 20 + self.navigationController.navigationBar.frame.size.height + i * buttonSize.height, buttonSize.width, buttonSize.height); 68 | [btn addTarget:self action:NSSelectorFromString(actions[i]) forControlEvents:UIControlEventTouchUpInside]; 69 | [btn setTitle:titles[i] forState:UIControlStateNormal]; 70 | [self.view addSubview:btn]; 71 | 72 | } 73 | } 74 | 75 | - (void)viewWillAppear:(BOOL)animated 76 | { 77 | [super viewWillAppear:animated]; 78 | } 79 | 80 | - (void)viewWillDisappear:(BOOL)animated 81 | { 82 | [super viewWillDisappear:animated]; 83 | } 84 | 85 | - (void)didReceiveMemoryWarning 86 | { 87 | [super didReceiveMemoryWarning]; 88 | // Dispose of any resources that can be recreated. 89 | } 90 | 91 | int runs_forever = THREAD_NUMBER; 92 | - (void)updateDatabaseOnMainThread 93 | { 94 | dispatch_async(dispatch_get_main_queue(), ^{ 95 | CoreDataEnvir *db = [CoreDataEnvir instance]; 96 | short testCounter = 0; 97 | NSLog(@"Start updating..."); 98 | while (runs_forever && testCounter >= 0) { 99 | testCounter ++; 100 | Team *team = [Team lastItemInContext:db usingPredicate:[NSPredicate predicateWithFormat:@"name==%@", @"com.cyblion"]]; 101 | team.number = @(testCounter); 102 | [db saveDataBase]; 103 | printf("update to \"%hd\".\n", testCounter); 104 | } 105 | NSLog(@"Stoped updating."); 106 | }); 107 | 108 | } 109 | 110 | - (void)runTestA:(dispatch_queue_t)queue withTimes:(unsigned int)times 111 | { 112 | //Every thread runs 101 times Request operation. 113 | int runTimes = times; 114 | dispatch_async(queue, ^{ 115 | CoreDataEnvir *db = [CoreDataEnvir instance]; 116 | [CoreDataEnvir setRescureDelegate:self]; 117 | 118 | NSString *queueLabel = [NSString stringWithCString:dispatch_queue_get_label(queue) encoding:NSUTF8StringEncoding]; 119 | 120 | if (!self.teamOnBackground) { 121 | self.teamOnBackground = [Team lastItemInContext:db]; 122 | } 123 | //Team *t = [Team lastItemInContext:db]; 124 | 125 | //for (int i = t.number.intValue; i < runTimes; i++) { 126 | int i = 0; 127 | for (;;) { 128 | Team *team = (Team *)[Team lastItemInContext:db]; 129 | 130 | i = team.number.intValue; 131 | i ++; 132 | 133 | if (team) { 134 | team.number = @(i); 135 | }else { 136 | team = [Team insertItemInContext:db fillData:^(Team *item) { 137 | item.name = queueLabel; 138 | item.number = @(0); 139 | }]; 140 | } 141 | [team saveTo:db]; 142 | 143 | if (team) { 144 | NSLog(@"testing queue :%@; team.number :%@", queueLabel, self.teamOnBackground.number); 145 | } 146 | 147 | if (i >= runTimes - 1) { 148 | //i = 0; 149 | break; 150 | } 151 | 152 | [NSThread sleepForTimeInterval:0.05]; 153 | } 154 | dispatch_semaphore_wait(self->__runs_sema, ~0ull); 155 | runs_forever--; 156 | dispatch_semaphore_signal(self->__runs_sema); 157 | NSLog(@"runs_forever :%d", runs_forever); 158 | }); 159 | } 160 | 161 | - (void)runTestB:(dispatch_queue_t)queue withTimes:(unsigned int)times 162 | { 163 | //Every thread runs 101 times CRUD operation. 164 | int runTimes = times; 165 | dispatch_async(queue, ^{ 166 | CoreDataEnvir *db = [CoreDataEnvir instance]; 167 | 168 | unsigned int c = counter; 169 | NSString *queueLabel = [NSString stringWithCString:dispatch_queue_get_label(queue) encoding:NSUTF8StringEncoding]; 170 | 171 | for (int i = 0; i < runTimes; i++) { 172 | Team *team = (Team *)[Team lastItemInContext:db usingPredicate:[NSPredicate predicateWithFormat:@"name==%@", queueLabel]]; 173 | 174 | //Delete item. 175 | if (team) { 176 | [team removeFrom:db]; 177 | team.number = @(0 + c * 10000); 178 | NSLog(@"testing queue :%@; team.number :%@", queueLabel, team.number); 179 | } 180 | else { 181 | //Inset item. 182 | [Team insertItemInContext:db fillData:^(Team *item) { 183 | item.name = queueLabel; 184 | item.number = @(0 + c * 10000); 185 | }]; 186 | } 187 | [db saveDataBase]; 188 | } 189 | dispatch_semaphore_wait(self->__runs_sema, ~0ull); 190 | runs_forever--; 191 | dispatch_semaphore_signal(self->__runs_sema); 192 | NSLog(@"runs_forever :%d", runs_forever); 193 | }); 194 | } 195 | 196 | int counter = 0; 197 | - (void)onClick_test:(id)sender 198 | { 199 | 200 | #if testing_case == TESTING_A 201 | 202 | if (runs_forever <= 0) { 203 | dispatch_semaphore_wait(__runs_sema, ~0ull); 204 | runs_forever = THREAD_NUMBER; 205 | dispatch_semaphore_signal(__runs_sema); 206 | [self updateDatabaseOnMainThread]; 207 | } 208 | 209 | for (int i = 0; i < THREAD_NUMBER; i++) { 210 | dispatch_queue_t q1 = NULL; 211 | //Start 20 thread for testing, every thread runs CRUD operation 101 times on Name "com.cyblion". 212 | q1 = dispatch_queue_create([[NSString stringWithFormat:@"com.cyblion.%d", i] cStringUsingEncoding:NSUTF8StringEncoding], NULL); 213 | 214 | if (q1) { 215 | [self runTestA:q1 withTimes:LOOP_NUMBER_PER_THREAD]; 216 | } 217 | //dispatch_release(q1); 218 | } 219 | 220 | #elif testing_case == TESTING_B 221 | 222 | for (int i = 0; i < THREAD_NUMBER; i++) { 223 | dispatch_queue_t q1 = NULL; 224 | 225 | //Start 'THREAD_NUMBER' thread for testing, every thread runs CRUD operation 'LOOP_NUMBER_PER_THREAD' times seperately. 226 | q1 = dispatch_queue_create([[NSString stringWithFormat:@"com.cyblion.%d", ++counter] cStringUsingEncoding:NSUTF8StringEncoding], NULL); 227 | if (q1) { 228 | [self runTestB:q1 withTimes:LOOP_NUMBER_PER_THREAD]; 229 | dispatch_release(q1); 230 | } 231 | } 232 | 233 | #elif testing_case == TESTING_C 234 | 235 | 236 | dispatch_queue_t q = dispatch_queue_create([[NSString stringWithFormat:@"com.cyblion.testing_c"] cStringUsingEncoding:NSUTF8StringEncoding], NULL); 237 | 238 | dispatch_async(q, ^{ 239 | int i = 0; 240 | 241 | for (i = 1; i <= 1024; i++) { 242 | NSLog(@"\n\n\n==========================="); 243 | NSLog(@"Instance number [%d]", i); 244 | #if 1 245 | CoreDataEnvir *cde = [CoreDataEnvir createInstanceShareingPersistence:NO]; 246 | if (!cde) { 247 | break; 248 | } 249 | #else 250 | //Pure manual code. 251 | NSManagedObjectContext * context = [[[NSManagedObjectContext alloc] init] autorelease]; 252 | [context setRetainsRegisteredObjects:NO]; 253 | [context setPropagatesDeletesAtEndOfEvent:NO]; 254 | [context setMergePolicy:NSOverwriteMergePolicy]; 255 | 256 | NSString *momdPath = [[NSBundle mainBundle] pathForResource:@"SampleModel" ofType:@"momd"]; 257 | NSURL *momdURL = [NSURL fileURLWithPath:momdPath]; 258 | NSManagedObjectModel *_m = [[[NSManagedObjectModel alloc] initWithContentsOfURL:momdURL] autorelease]; 259 | if (!_m) { 260 | NSLog(@"Reached number %d", i); 261 | break; 262 | } 263 | 264 | NSPersistentStoreCoordinator *psc = [[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_m] autorelease]; 265 | 266 | NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 267 | [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 268 | [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, 269 | nil]; 270 | 271 | NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 272 | 273 | [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/db.sqlite", path]] options:options error:nil]; 274 | [context setPersistentStoreCoordinator:psc]; 275 | #endif 276 | if (i + 1 >= 1025) { 277 | break; 278 | } 279 | } 280 | 281 | dispatch_async(dispatch_get_main_queue(), ^{ 282 | NSString *message = [NSString stringWithFormat:@"Reaching number %d", i]; 283 | UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"" message:message delegate:nil cancelButtonTitle:@"Close" otherButtonTitles: nil] autorelease]; 284 | [alert show]; 285 | }); 286 | 287 | }); 288 | dispatch_release(q); 289 | 290 | 291 | #elif TESTING_D 292 | NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 293 | NSString *filePath = [NSString stringWithFormat:@"%@/db.sqlite", path]; 294 | 295 | NSInputStream *ises[1024]; 296 | 297 | for (int i = 1; i <= 1024; i++) { 298 | NSLog(@"open :%d", i); 299 | NSInputStream *is = [[NSInputStream inputStreamWithFileAtPath:filePath] retain]; 300 | [is open]; 301 | ises[i - 1] = is; 302 | } 303 | 304 | uint8_t buffer[1024]; 305 | for (int i = 1; i <= 1024; i++) { 306 | NSLog(@"read :%d", i); 307 | [ises[i - 1] read:buffer maxLength:1024]; 308 | } 309 | 310 | #endif 311 | 312 | 313 | } 314 | 315 | - (void)onClick_clearAll:(id)sender 316 | { 317 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 318 | CoreDataEnvir *db = [CoreDataEnvir instance]; 319 | 320 | NSArray *teams = [Team itemsInContext:db]; 321 | [db deleteDataItems:teams]; 322 | 323 | NSArray *members = [Member itemsInContext:db]; 324 | [db deleteDataItems:members]; 325 | 326 | [db saveDataBase]; 327 | }); 328 | } 329 | 330 | - (void)onClick_look:(id)sender 331 | { 332 | NSArray *teams = [Team items]; 333 | NSArray *members = [Member items]; 334 | 335 | Team *t = [Team lastItem]; 336 | 337 | if (!self.teamOnMainThread) { 338 | self.teamOnMainThread = [Team lastItem]; 339 | } 340 | 341 | NSString *message = [NSString stringWithFormat:@"teams :%lu\nmembers :%lu\nTeam name:%@ number:%@\n t number:%@", [teams count], [members count], self.teamOnMainThread.name, self.teamOnMainThread.number, t.number]; 342 | NSLog(@"team background :%@", self.teamOnBackground); 343 | // t.number = @(0); 344 | // [t save]; 345 | 346 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:message delegate:Nil cancelButtonTitle:@"Close" otherButtonTitles: nil]; 347 | [alert show]; 348 | } 349 | 350 | - (BOOL)shouldRescureCoreData 351 | { 352 | return YES; 353 | } 354 | 355 | - (void)didStartRescureCoreData:(CoreDataEnvir *)cde 356 | { 357 | 358 | } 359 | 360 | - (void)didFinishedRescuringCoreData:(CoreDataEnvir *)cde 361 | { 362 | 363 | } 364 | 365 | - (void)rescureFailed:(CoreDataEnvir *)cde 366 | { 367 | 368 | } 369 | 370 | 371 | @end 372 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/CoreDataEnvirSample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "Team.h" 6 | #import "Member.h" 7 | #if __has_include() 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/RelationshipViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RelationshipViewController.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RelationshipViewController : UIViewController 12 | 13 | - (IBAction)onClick_init:(id)sender; 14 | - (IBAction)onClick_load:(id)sender; 15 | - (IBAction)onClick_clearAll:(id)sender; 16 | - (IBAction)onClick_clearTeams:(id)sender; 17 | - (IBAction)onClick_clearMembers:(id)sender; 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/RelationshipViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RelationshipViewController.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "RelationshipViewController.h" 10 | 11 | //#import "CoreDataEnvirHeader.h" 12 | #import 13 | @import CoreDataEnvir; 14 | #import "Team.h" 15 | #import "Member.h" 16 | 17 | #define BUTTONS_NUMBER 5 18 | 19 | @interface RelationshipViewController () 20 | 21 | @end 22 | 23 | @implementation RelationshipViewController 24 | 25 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 26 | { 27 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 28 | if (self) { 29 | // Custom initialization 30 | 31 | } 32 | return self; 33 | } 34 | 35 | - (void)viewDidLoad 36 | { 37 | [super viewDidLoad]; 38 | // Do any additional setup after loading the view. 39 | self.view.backgroundColor = [UIColor lightGrayColor]; 40 | 41 | NSString * actions[BUTTONS_NUMBER] = {@"onClick_init:", @"onClick_load:", @"onClick_clearAll:", @"onClick_clearTeams:", @"onClick_clearMembers:"}; 42 | NSString * titles[BUTTONS_NUMBER] = {@"Init", @"Watch", @"Clear All", @"Clear Teams", @"Cleaer Members"}; 43 | 44 | CGSize buttonSize = CGSizeMake(180, 60); 45 | 46 | for (int i = 0; i < BUTTONS_NUMBER; i++) { 47 | 48 | UIButton *btn = [[UIButton alloc] initWithFrame:CGRectZero]; 49 | btn.frame = CGRectMake(20, 20 + self.navigationController.navigationBar.frame.size.height + i * buttonSize.height, buttonSize.width, buttonSize.height); 50 | [btn addTarget:self action:NSSelectorFromString(actions[i]) forControlEvents:UIControlEventTouchUpInside]; 51 | [btn setTitle:titles[i] forState:UIControlStateNormal]; 52 | [self.view addSubview:btn]; 53 | 54 | } 55 | 56 | } 57 | 58 | - (void)didReceiveMemoryWarning 59 | { 60 | [super didReceiveMemoryWarning]; 61 | // Dispose of any resources that can be recreated. 62 | } 63 | 64 | - (void)onClick_init:(id)sender 65 | { 66 | Team *team1 = [Team insertItem]; 67 | for (int i = 0; i < 20; i ++) { 68 | Member *mem = [Member insertItemWithFillingBlock:^(Member *item) { 69 | item.name = [NSString stringWithFormat:@"T1_M%d", i]; 70 | item.belongedTeam = team1; 71 | }]; 72 | [team1 addMembersObject:mem]; 73 | [mem save]; 74 | } 75 | 76 | Team *team2 = [Team insertItem]; 77 | for (int i = 0; i < 20; i ++) { 78 | Member *mem = [Member insertItemWithFillingBlock:^(Member *item) { 79 | item.name = [NSString stringWithFormat:@"T2_M%d", i]; 80 | item.belongedTeam = team2; 81 | }]; 82 | [team2 addMembersObject:mem]; 83 | [mem save]; 84 | } 85 | } 86 | 87 | - (void)onClick_load:(id)sender 88 | { 89 | CoreDataEnvir *db = [CoreDataEnvir instance]; 90 | NSArray *teams = [Team itemsInContext:db]; 91 | NSArray *members = [Member itemsInContext:db]; 92 | 93 | int members_c = 0; 94 | for (Team *t in teams) { 95 | members_c += [t.members count]; 96 | } 97 | NSString *message = [NSString stringWithFormat:@"teams %lu\nmembers of teams :%d\ntotal members :%lu.", [teams count], members_c, [members count]]; 98 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:message delegate:Nil cancelButtonTitle:@"Close" otherButtonTitles: nil]; 99 | [alert show]; 100 | 101 | } 102 | 103 | - (void)onClick_clearAll:(id)sender 104 | { 105 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 106 | CoreDataEnvir *db = [CoreDataEnvir instance]; 107 | 108 | NSArray *members = [Member itemsInContext:db]; 109 | [members makeObjectsPerformSelector:@selector(removeFrom:) withObject:db]; 110 | 111 | NSArray *teams = [Team itemsInContext:db]; 112 | [teams makeObjectsPerformSelector:@selector(removeFrom:) withObject:db]; 113 | 114 | 115 | [db saveDataBase]; 116 | }); 117 | 118 | } 119 | 120 | - (void)onClick_clearTeams:(id)sender 121 | { 122 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 123 | CoreDataEnvir *db = [CoreDataEnvir instance]; 124 | 125 | NSArray *teams = [Team itemsInContext:db]; 126 | [teams makeObjectsPerformSelector:@selector(removeFrom:) withObject:db]; 127 | for (Team *t in teams) { 128 | t.members = nil; 129 | [t removeFrom:db]; 130 | } 131 | 132 | [db saveDataBase]; 133 | }); 134 | 135 | } 136 | 137 | - (void)onClick_clearMembers:(id)sender 138 | { 139 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 140 | CoreDataEnvir *db = [CoreDataEnvir instance]; 141 | 142 | NSArray *members = [Member itemsInContext:db]; 143 | for (Member *m in members) { 144 | m.belongedTeam = nil; 145 | [m removeFrom:db]; 146 | } 147 | 148 | [db saveDataBase]; 149 | }); 150 | 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/CoreDataEnvirSample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/CoreDataEnvirSample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'CoreDataEnvirSample' target in the 'CoreDataEnvirSample' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_4_0 8 | #warning "This project uses features only available in iOS SDK 4.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #import 15 | #endif 16 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehengxu/CoreDataEnvir/ee1cfa305b068f12c33d92ae0636cdea44ced7cb/CoreDataEnvirSample/Supporting Files/Default-568h@2x.png -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehengxu/CoreDataEnvir/ee1cfa305b068f12c33d92ae0636cdea44ced7cb/CoreDataEnvirSample/Supporting Files/Default.png -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehengxu/CoreDataEnvir/ee1cfa305b068f12c33d92ae0636cdea44ced7cb/CoreDataEnvirSample/Supporting Files/Default@2x.png -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/Member.h: -------------------------------------------------------------------------------- 1 | // 2 | // Member.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class Team; 13 | 14 | @interface Member : NSManagedObject 15 | 16 | @property (nonatomic, retain) NSNumber * age; 17 | @property (nonatomic, retain) NSDate * birthday; 18 | @property (nonatomic, retain) NSString * name; 19 | @property (nonatomic, retain) NSString * phonenum; 20 | @property (nonatomic, retain) Team *belongedTeam; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/Member.m: -------------------------------------------------------------------------------- 1 | // 2 | // Member.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "Member.h" 10 | #import "Team.h" 11 | 12 | 13 | @implementation Member 14 | 15 | @dynamic age; 16 | @dynamic birthday; 17 | @dynamic name; 18 | @dynamic phonenum; 19 | @dynamic belongedTeam; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/SampleModel.xcdatamodeld/SampleModel.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/Team.h: -------------------------------------------------------------------------------- 1 | // 2 | // Team.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class Member; 13 | 14 | @interface Team : NSManagedObject 15 | 16 | @property (nonatomic, retain) NSString * name; 17 | @property (nonatomic, retain) NSNumber * number; 18 | @property (nonatomic, retain) NSSet *members; 19 | @end 20 | 21 | @interface Team (CoreDataGeneratedAccessors) 22 | 23 | - (void)addMembersObject:(Member *)value; 24 | - (void)removeMembersObject:(Member *)value; 25 | - (void)addMembers:(NSSet *)values; 26 | - (void)removeMembers:(NSSet *)values; 27 | @end 28 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/Team.m: -------------------------------------------------------------------------------- 1 | // 2 | // Team.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-9-26. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "Team.h" 10 | #import "Member.h" 11 | 12 | 13 | @implementation Team 14 | 15 | @dynamic name; 16 | @dynamic number; 17 | @dynamic members; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/demo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Concurrency 6 | Relationship 7 | Swift 8 | 9 | 10 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/Supporting Files/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-4-7. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/SwiftViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftViewController.swift 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 2020/9/14. 6 | // Copyright © 2020 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreDataEnvir 11 | 12 | @objc(SwiftViewController) 13 | class SwiftViewController: UIViewController { 14 | 15 | @objc override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | CoreDataEnvir.mainInstance() 19 | print("Team.totalCount:", Team.totalCount()) 20 | print("Member.totalCount:", Member.totalCount()) 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-4-7. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CoreDataEnvir.h" 11 | 12 | @interface ViewController : UIViewController 13 | < 14 | UITableViewDelegate, UITableViewDataSource 15 | > 16 | { 17 | } 18 | @property (nonatomic, readonly, retain) NSArray *demonNames; 19 | @property (nonatomic, retain) UITableView *tableView; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng.Xu on 13-4-7. 6 | // Copyright (c) 2013年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | //#import "CoreDataEnvir.h" 11 | //#import "Team.h" 12 | 13 | #define THREAD_NUMBER 20 14 | #define LOOP_NUMBER_PER_THREAD 101 15 | #define TESTING_A 1 16 | #define TESTING_B 2 17 | #define testing_case TESTING_A 18 | 19 | @interface ViewController () 20 | 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | @synthesize demonNames = _demonNames; 26 | 27 | - (void)viewDidLoad 28 | { 29 | [super viewDidLoad]; 30 | // Do any additional setup after loading the view, typically from a nib. 31 | self.tableView.delegate = self; 32 | self.tableView.dataSource = self; 33 | self.tableView.frame = self.view.bounds; 34 | self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 35 | [self.view addSubview:self.tableView]; 36 | } 37 | 38 | - (void)viewWillAppear:(BOOL)animated 39 | { 40 | [self.tableView reloadData]; 41 | } 42 | 43 | - (void)viewWillDisappear:(BOOL)animated 44 | { 45 | } 46 | 47 | - (void)didReceiveMemoryWarning 48 | { 49 | [super didReceiveMemoryWarning]; 50 | // Dispose of any resources that can be recreated. 51 | } 52 | 53 | #pragma mark - lazy loading 54 | 55 | - (NSArray *)demonNames 56 | { 57 | if (!_demonNames) { 58 | _demonNames = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"demo" ofType:@"plist"]]; 59 | } 60 | return _demonNames; 61 | } 62 | 63 | - (UITableView *)tableView 64 | { 65 | if (!_tableView) { 66 | _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; 67 | } 68 | return _tableView; 69 | } 70 | 71 | #pragma mark - table view delegate & data source 72 | 73 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 74 | { 75 | return 1; 76 | } 77 | 78 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 79 | { 80 | return [self.demonNames count]; 81 | } 82 | 83 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 84 | { 85 | NSString *identifier = @"_table_view_cell_identifier"; 86 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 87 | 88 | if (cell == nil) { 89 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; 90 | } 91 | 92 | if (cell) { 93 | //Todo:Config cell object. 94 | 95 | cell.textLabel.text = [self.demonNames objectAtIndex:indexPath.row]; 96 | } 97 | 98 | return cell; 99 | } 100 | 101 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 102 | { 103 | NSString* name = [NSString stringWithFormat:@"%@ViewController", [self.demonNames objectAtIndex:indexPath.row]]; 104 | Class theClass = NSClassFromString(name); 105 | 106 | <<<<<<< HEAD 107 | UIViewController *vc = [[[theClass alloc] init] autorelease]; 108 | ======= 109 | UIViewController *vc = [[theClass alloc] init]; 110 | >>>>>>> feature/arc 111 | if (vc) { 112 | [self.navigationController pushViewController:vc animated:YES]; 113 | }else { 114 | NSLog(@"class: %@ not found.", name); 115 | } 116 | [[self.tableView cellForRowAtIndexPath:indexPath] setSelected:NO animated:YES]; 117 | } 118 | 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /CoreDataEnvirSample/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dehengxu/CoreDataEnvir/ee1cfa305b068f12c33d92ae0636cdea44ced7cb/CoreDataEnvirSample/zh-Hans.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /CoreDataEnvirSampleTests/CoreDataEnvirTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvirTests.m 3 | // CoreDataEnvirSampleTests 4 | // 5 | // Created by NicholasXu on 2020/9/18. 6 | // Copyright © 2020 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CoreDataEnvirTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation CoreDataEnvirTests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | - (void)tearDown { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | - (void)testExample { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | - (void)testPerformanceExample { 31 | // This is an example of a performance test case. 32 | [self measureBlock:^{ 33 | // Put the code you want to measure the time of here. 34 | }]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /CoreDataEnvirSampleTests/Supporting Files/CoreDataEnvirSampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CoreDataEnvirSampleTests/Supporting Files/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /CoreDataEnvirSampleTests/Supporting Files/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /CoreDataEnvirTests/CoreDataEnvirTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvirTests.m 3 | // CoreDataEnvirTests 4 | // 5 | // Created by NicholasXu on 2020/9/21. 6 | // Copyright © 2020 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CoreDataEnvirTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation CoreDataEnvirTests 16 | 17 | - (void)setUp { 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | - (void)tearDown { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | - (void)testExample { 26 | // This is an example of a functional test case. 27 | // Use XCTAssert and related functions to verify your tests produce the correct results. 28 | } 29 | 30 | - (void)testPerformanceExample { 31 | // This is an example of a performance test case. 32 | [self measureBlock:^{ 33 | // Put the code you want to measure the time of here. 34 | }]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /CoreDataEnvirTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011/05/25 Deheng.Xu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Member+CoreDataClass.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Member+CoreDataClass.swift 3 | // 4 | // 5 | // Created by NicholasXu on 2020/9/14. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | import CoreDaaEnvir 12 | 13 | @objc(Member) 14 | public class Member: NSManagedObject { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Member+CoreDataProperties.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Member+CoreDataProperties.swift 3 | // 4 | // 5 | // Created by NicholasXu on 2020/9/14. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | 12 | 13 | extension Member { 14 | 15 | @nonobjc public class func fetchRequest() -> NSFetchRequest { 16 | return NSFetchRequest(entityName: "Member") 17 | } 18 | 19 | @NSManaged public var age: NSNumber? 20 | @NSManaged public var birthday: Date? 21 | @NSManaged public var name: String? 22 | @NSManaged public var phonenum: String? 23 | @NSManaged public var belongedTeam: Team? 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ObjcUML/Scripts/d3js-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Michael Bostock 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * The name Michael Bostock may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /ObjcUML/Scripts/parse.js: -------------------------------------------------------------------------------- 1 | // =================================================== 2 | // =============== PARSING =========================== 3 | // =================================================== 4 | // Input 5 | // { links : [ {source: sourceName, dest : destName} * ] } 6 | // Output: 7 | !function () { 8 | var objcdv = { 9 | version: "0.0.1" 10 | }; 11 | objcdv.parse_dependencies_graph = function (dependencies, regexp_color_matchers) { 12 | 13 | var nodes = []; 14 | var links = []; 15 | 16 | var nodesSet = {}; 17 | var prefixes = {}; 18 | 19 | var node_index = 0; 20 | 21 | // Parse all dependencies 22 | // In format 23 | 24 | var input_links = dependencies.links; 25 | 26 | var updatePrefixesDistribution = function(name) { 27 | var prefix = name.substring(0, 2); 28 | if (!(prefix in prefixes)) { 29 | prefixes[prefix] = 1; 30 | } else { 31 | prefixes[prefix]++; 32 | } 33 | } 34 | 35 | for (var i = 0; i < input_links.length; i++) { 36 | var link = input_links[i]; 37 | 38 | var source_node = nodesSet[link.source]; 39 | if (source_node == null) { 40 | nodesSet[link.source] = source_node = { idx :node_index++, name: link.source, source: 1, dest: 0 } 41 | } 42 | source_node.source++; 43 | 44 | var dest_node = nodesSet[link.dest]; 45 | if (dest_node == null) { 46 | nodesSet[link.dest] = dest_node = { idx :node_index++, name: link.dest, source: 0, dest: 1 } 47 | } 48 | dest_node.dest++; 49 | 50 | 51 | // Grouping by prefixes 52 | updatePrefixesDistribution(link.source); 53 | updatePrefixesDistribution(link.dest); 54 | 55 | // Remapping links objects 56 | links.push({ 57 | 58 | // d3 js properties 59 | source: source_node.idx, 60 | target: dest_node.idx, 61 | 62 | // Additional link information 63 | sourceNode: source_node, 64 | targetNode: dest_node 65 | }); 66 | 67 | console.log("Pushing link : source=" + source_node.idx + ", target=" + dest_node.idx); 68 | } 69 | 70 | 71 | // Sorting prefixes, based on theirs frequency 72 | var prefixes_arr = []; 73 | for (var key in prefixes) { 74 | prefixes_arr.push({key: key, value: prefixes[key] }); 75 | } 76 | var sorted_prefixes = prefixes_arr.slice(0).sort(function (a, b) { 77 | return b.value - a.value; 78 | }); 79 | 80 | // If we dont' have regexp_color_matchers, we'll set them up, based on prefixes 81 | var group_regexp_identifiers = regexp_color_matchers; 82 | if (group_regexp_identifiers == null) { 83 | group_regexp_identifiers = []; 84 | for (var i = 0; i < sorted_prefixes.length; i++) { 85 | group_regexp_identifiers.push("^" + sorted_prefixes[i].key+".*"); 86 | } 87 | } 88 | 89 | // Setting up nodes groups, based on the group_regexp_identifiers 90 | var idx = 0; 91 | for (var p in nodesSet) { 92 | 93 | node = nodesSet[p]; 94 | node.group = 0; 95 | node.weight = node.source; // Calculating node weignt, based on the amount of item it depends on 96 | 97 | for (var regexp_index = 0; regexp_index < group_regexp_identifiers.length; regexp_index++) { 98 | var re = new RegExp(group_regexp_identifiers[regexp_index], ""); 99 | if (p.match(re)) { 100 | node.group = regexp_index + 1; 101 | break; 102 | } 103 | } 104 | 105 | nodes.push(node); 106 | console.log(" Pushing node : IDX=" + idx + ", name=" + p + ", groupId=" + node.group + ", source=" + node.source + ", dest=" + node.dest + ", weight=" + node.weight); 107 | idx++; 108 | } 109 | 110 | return { nodes : nodes, links: links }; 111 | } 112 | 113 | if (typeof define === "function" && define.amd) { 114 | define(objcdv); 115 | } else if (typeof module === "object" && module.exports) { 116 | module.exports = objcdv; 117 | } else { 118 | this.objcdv = objcdv; 119 | } 120 | }(); 121 | 122 | -------------------------------------------------------------------------------- /ObjcUML/dependency.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .node.filtered { 4 | fill-opacity:0.3; 5 | stroke-opacity:0.3; 6 | } 7 | 8 | text.filtered { 9 | fill-opacity:0; 10 | stroke-opacity:0; 11 | } 12 | 13 | .link.filtered { 14 | stroke: #ddd; 15 | fill-opacity:0.1; 16 | stroke-opacity:0.1; 17 | } 18 | 19 | .node { 20 | stroke: #000; 21 | stroke-width: 0.5px; 22 | } 23 | 24 | .link { 25 | stroke: #999; 26 | stroke-opacity: .6; 27 | fill: none; 28 | stroke-width: 1.5px; 29 | pointer-events: none; 30 | } 31 | 32 | .marker#default { 33 | stroke: #999; 34 | fill:#999; 35 | pointer-events: none; 36 | } 37 | 38 | .marker#dependency { 39 | stroke: #900; 40 | fill:#900; 41 | pointer-events: none; 42 | } 43 | 44 | .marker#dependants { 45 | stroke: #090; 46 | fill:#090; 47 | pointer-events: none; 48 | } 49 | 50 | 51 | text { 52 | stroke: #000; 53 | stroke-width: 0.5px; 54 | text-anchor:middle; 55 | font: 10px sans-serif; 56 | font-weight: normal; 57 | font-style: normal; 58 | pointer-events: none; 59 | } 60 | 61 | form { 62 | position: absolute; 63 | right: 10px; 64 | top: 10px; 65 | } -------------------------------------------------------------------------------- /ObjcUML/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 |
22 |
23 | 24 |
25 | 26 | 27 | 416 | 417 | 448 | 449 | 450 | -------------------------------------------------------------------------------- /ObjcUML/origin.js: -------------------------------------------------------------------------------- 1 | var dependencies = { 2 | links: 3 | [ 4 | { "source" : "AppDelegate", "dest" : "CoreDataEnvir" }, 5 | { "source" : "AppDelegate", "dest" : "ViewController" }, 6 | { "source" : "ConcurrencyViewController", "dest" : "CoreDataEnvir" }, 7 | { "source" : "ConcurrencyViewController", "dest" : "Member" }, 8 | { "source" : "ConcurrencyViewController", "dest" : "Team" }, 9 | { "source" : "CoreDataEnvir_Background", "dest" : "CoreDataEnvir" }, 10 | { "source" : "main", "dest" : "AppDelegate" }, 11 | { "source" : "RelationshipViewController", "dest" : "CoreDataEnvir" }, 12 | { "source" : "RelationshipViewController", "dest" : "Member" }, 13 | { "source" : "RelationshipViewController", "dest" : "Team" }, 14 | { "source" : "AppDelegate", "dest" : "ViewController" }, 15 | { "source" : "ConcurrencyViewController", "dest" : "Team" }, 16 | { "source" : "ConcurrencyViewController", "dest" : "CoreDataEnvir" }, 17 | { "source" : "CoreDataEnvir_Background", "dest" : "CoreDataEnvir" }, 18 | { "source" : "Member", "dest" : "Team" }, 19 | { "source" : "RelationshipViewController", "dest" : "Team" }, 20 | { "source" : "RelationshipViewController", "dest" : "Member" }, 21 | { "source" : "RelationshipViewController", "dest" : "CoreDataEnvir" }, 22 | ] 23 | } 24 | ; 25 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '9.0' 3 | 4 | #target 'CoreDataEnvirFramework' do 5 | # # Comment the next line if you don't want to use dynamic frameworks 6 | # use_frameworks! 7 | # 8 | # # Pods for CoreDataEnvir 9 | # 10 | # target 'CoreDataEnvirFrameworkTests' do 11 | # # Pods for testing 12 | # end 13 | # 14 | #end 15 | 16 | target 'CoreDataEnvirSample' do 17 | # Comment the next line if you don't want to use dynamic frameworks 18 | use_frameworks! 19 | 20 | # Pods for CoreDataEnvirSample 21 | pod 'CoreDataEnvir', :path => './' 22 | end 23 | 24 | target 'CoreDataEnvirSampleTests' do 25 | # Comment the next line if you don't want to use dynamic frameworks 26 | use_frameworks! 27 | 28 | # Pods for CoreDataEnvirSampleTests 29 | 30 | end 31 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CoreDataEnvir (0.13.0-beta.1) 3 | 4 | DEPENDENCIES: 5 | - CoreDataEnvir (from `./`) 6 | 7 | EXTERNAL SOURCES: 8 | CoreDataEnvir: 9 | :path: "./" 10 | 11 | SPEC CHECKSUMS: 12 | CoreDataEnvir: b1e194fb4f9c0c1379e41aa279914e846532e818 13 | 14 | PODFILE CHECKSUM: ca1c3555763228eec892767a892b60d23cd1cb85 15 | 16 | COCOAPODS: 1.9.3 17 | -------------------------------------------------------------------------------- /Pods/Local Podspecs/CoreDataEnvir.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CoreDataEnvir", 3 | "version": "0.13.0-beta.1", 4 | "summary": "CoreDataEnvir is a CoreData wrapper which use CoreData in convient way and supply thread safe in concurrenct programming.", 5 | "description": "CoreDataEnvir is a CoreData wrapper which use CoreData in convient way and supply thread safe in concurrenct programming. You can use it concurrenctly,run seperate CoreDataEnvir instance on one thread.", 6 | "homepage": "https://dehengxu.github.io/CoreDataEnvir", 7 | "module_name": "CoreDataEnvir", 8 | "license": "MIT", 9 | "authors": { 10 | "DehengXu": "dehengxu@outlook.com" 11 | }, 12 | "social_media_url": "https://github.com/dehengxu", 13 | "platforms": { 14 | "ios": "10.0" 15 | }, 16 | "source": { 17 | "git": "https://github.com/dehengxu/CoreDataEnvir.git", 18 | "tag": "0.13.0-beta.1" 19 | }, 20 | "source_files": [ 21 | "src/CoreDataEnvir/*.h", 22 | "src/CoreDataEnvir/**/*.{h,m}" 23 | ], 24 | "public_header_files": "src/CoreDataEnvir/**/*.h", 25 | "frameworks": "CoreData", 26 | "requires_arc": true, 27 | "info_plist": { 28 | "CFBundleIdentifier": "com.dehengxu.CoreDataEnvir" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CoreDataEnvir (0.13.0-beta.1) 3 | 4 | DEPENDENCIES: 5 | - CoreDataEnvir (from `./`) 6 | 7 | EXTERNAL SOURCES: 8 | CoreDataEnvir: 9 | :path: "./" 10 | 11 | SPEC CHECKSUMS: 12 | CoreDataEnvir: b1e194fb4f9c0c1379e41aa279914e846532e818 13 | 14 | PODFILE CHECKSUM: ca1c3555763228eec892767a892b60d23cd1cb85 15 | 16 | COCOAPODS: 1.9.3 17 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/dehengxu.xcuserdatad/xcschemes/CoreDataEnvir.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/dehengxu.xcuserdatad/xcschemes/Pods-CoreDataEnvirSample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/dehengxu.xcuserdatad/xcschemes/Pods-CoreDataEnvirSampleTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/dehengxu.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CoreDataEnvir.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-CoreDataEnvirSample.xcscheme 13 | 14 | isShown 15 | 16 | 17 | Pods-CoreDataEnvirSampleTests.xcscheme 18 | 19 | isShown 20 | 21 | 22 | 23 | SuppressBuildableAutocreation 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CoreDataEnvir/CoreDataEnvir-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.dehengxu.CoreDataEnvir 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.13.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CoreDataEnvir/CoreDataEnvir-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_CoreDataEnvir : NSObject 3 | @end 4 | @implementation PodsDummy_CoreDataEnvir 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CoreDataEnvir/CoreDataEnvir-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CoreDataEnvir/CoreDataEnvir-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "CoreDataEnvir.h" 14 | #import "CoreDataEnvirDescriptor.h" 15 | #import "CoreDataEnvirHeader.h" 16 | #import "CoreDataEnvirObserver.h" 17 | #import "CoreDataEnvir_Background.h" 18 | #import "CoreDataEnvir_Main.h" 19 | #import "CoreDataRescureDelegate.h" 20 | #import "NSManagedObject_Background.h" 21 | #import "NSManagedObject_Convenient.h" 22 | #import "NSManagedObject_MainThread.h" 23 | #import "CoreDataEnvir_Private.h" 24 | 25 | FOUNDATION_EXPORT double CoreDataEnvirVersionNumber; 26 | FOUNDATION_EXPORT const unsigned char CoreDataEnvirVersionString[]; 27 | 28 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CoreDataEnvir/CoreDataEnvir.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/CoreDataEnvir 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "CoreData" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CoreDataEnvir/CoreDataEnvir.modulemap: -------------------------------------------------------------------------------- 1 | framework module CoreDataEnvir { 2 | umbrella header "CoreDataEnvir-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/CoreDataEnvir/CoreDataEnvir.release.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/CoreDataEnvir 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "CoreData" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## CoreDataEnvir 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2011/05/25 Deheng.Xu 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | 28 | Generated by CocoaPods - https://cocoapods.org 29 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2011/05/25 Deheng.Xu 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in 29 | all copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 37 | THE SOFTWARE. 38 | 39 | License 40 | MIT 41 | Title 42 | CoreDataEnvir 43 | Type 44 | PSGroupSpecifier 45 | 46 | 47 | FooterText 48 | Generated by CocoaPods - https://cocoapods.org 49 | Title 50 | 51 | Type 52 | PSGroupSpecifier 53 | 54 | 55 | StringsTable 56 | Acknowledgements 57 | Title 58 | Acknowledgements 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_CoreDataEnvirSample : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_CoreDataEnvirSample 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/CoreDataEnvir/CoreDataEnvir.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CoreDataEnvir.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/CoreDataEnvir/CoreDataEnvir.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CoreDataEnvir.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | 23 | # Used as a return value for each invocation of `strip_invalid_archs` function. 24 | STRIP_BINARY_RETVAL=0 25 | 26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 29 | 30 | # Copies and strips a vendored framework 31 | install_framework() 32 | { 33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 34 | local source="${BUILT_PRODUCTS_DIR}/$1" 35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 37 | elif [ -r "$1" ]; then 38 | local source="$1" 39 | fi 40 | 41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 42 | 43 | if [ -L "${source}" ]; then 44 | echo "Symlinked..." 45 | source="$(readlink "${source}")" 46 | fi 47 | 48 | # Use filter instead of exclude so missing patterns don't throw errors. 49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 51 | 52 | local basename 53 | basename="$(basename -s .framework "$1")" 54 | binary="${destination}/${basename}.framework/${basename}" 55 | 56 | if ! [ -r "$binary" ]; then 57 | binary="${destination}/${basename}" 58 | elif [ -L "${binary}" ]; then 59 | echo "Destination binary is symlinked..." 60 | dirname="$(dirname "${binary}")" 61 | binary="${dirname}/$(readlink "${binary}")" 62 | fi 63 | 64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 66 | strip_invalid_archs "$binary" 67 | fi 68 | 69 | # Resign the code if required by the build settings to avoid unstable apps 70 | code_sign_if_enabled "${destination}/$(basename "$1")" 71 | 72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 74 | local swift_runtime_libs 75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 76 | for lib in $swift_runtime_libs; do 77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 79 | code_sign_if_enabled "${destination}/${lib}" 80 | done 81 | fi 82 | } 83 | 84 | # Copies and strips a vendored dSYM 85 | install_dsym() { 86 | local source="$1" 87 | warn_missing_arch=${2:-true} 88 | if [ -r "$source" ]; then 89 | # Copy the dSYM into the targets temp dir. 90 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 91 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 92 | 93 | local basename 94 | basename="$(basename -s .dSYM "$source")" 95 | binary_name="$(ls "$source/Contents/Resources/DWARF")" 96 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" 97 | 98 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 99 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 100 | strip_invalid_archs "$binary" "$warn_missing_arch" 101 | fi 102 | 103 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 104 | # Move the stripped file into its final destination. 105 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 106 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 107 | else 108 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 109 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 110 | fi 111 | fi 112 | } 113 | 114 | # Copies the bcsymbolmap files of a vendored framework 115 | install_bcsymbolmap() { 116 | local bcsymbolmap_path="$1" 117 | local destination="${BUILT_PRODUCTS_DIR}" 118 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 119 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 120 | } 121 | 122 | # Signs a framework with the provided identity 123 | code_sign_if_enabled() { 124 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 125 | # Use the current code_sign_identity 126 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 127 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 128 | 129 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 130 | code_sign_cmd="$code_sign_cmd &" 131 | fi 132 | echo "$code_sign_cmd" 133 | eval "$code_sign_cmd" 134 | fi 135 | } 136 | 137 | # Strip invalid architectures 138 | strip_invalid_archs() { 139 | binary="$1" 140 | warn_missing_arch=${2:-true} 141 | # Get architectures for current target binary 142 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 143 | # Intersect them with the architectures we are building for 144 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 145 | # If there are no archs supported by this binary then warn the user 146 | if [[ -z "$intersected_archs" ]]; then 147 | if [[ "$warn_missing_arch" == "true" ]]; then 148 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 149 | fi 150 | STRIP_BINARY_RETVAL=0 151 | return 152 | fi 153 | stripped="" 154 | for arch in $binary_archs; do 155 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 156 | # Strip non-valid architectures in-place 157 | lipo -remove "$arch" -output "$binary" "$binary" 158 | stripped="$stripped $arch" 159 | fi 160 | done 161 | if [[ "$stripped" ]]; then 162 | echo "Stripped $binary of architectures:$stripped" 163 | fi 164 | STRIP_BINARY_RETVAL=1 165 | } 166 | 167 | install_artifact() { 168 | artifact="$1" 169 | base="$(basename "$artifact")" 170 | case $base in 171 | *.framework) 172 | install_framework "$artifact" 173 | ;; 174 | *.dSYM) 175 | # Suppress arch warnings since XCFrameworks will include many dSYM files 176 | install_dsym "$artifact" "false" 177 | ;; 178 | *.bcsymbolmap) 179 | install_bcsymbolmap "$artifact" 180 | ;; 181 | *) 182 | echo "error: Unrecognized artifact "$artifact"" 183 | ;; 184 | esac 185 | } 186 | 187 | copy_artifacts() { 188 | file_list="$1" 189 | while read artifact; do 190 | install_artifact "$artifact" 191 | done <$file_list 192 | } 193 | 194 | ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt" 195 | if [ -r "${ARTIFACT_LIST_FILE}" ]; then 196 | copy_artifacts "${ARTIFACT_LIST_FILE}" 197 | fi 198 | 199 | if [[ "$CONFIGURATION" == "Debug" ]]; then 200 | install_framework "${BUILT_PRODUCTS_DIR}/CoreDataEnvir/CoreDataEnvir.framework" 201 | fi 202 | if [[ "$CONFIGURATION" == "Release" ]]; then 203 | install_framework "${BUILT_PRODUCTS_DIR}/CoreDataEnvir/CoreDataEnvir.framework" 204 | fi 205 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 206 | wait 207 | fi 208 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_CoreDataEnvirSampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_CoreDataEnvirSampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CoreDataEnvir" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CoreDataEnvir/CoreDataEnvir.framework/Headers" 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_LDFLAGS = $(inherited) -framework "CoreData" -framework "CoreDataEnvir" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_CoreDataEnvirSample { 2 | umbrella header "Pods-CoreDataEnvirSample-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSample/Pods-CoreDataEnvirSample.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CoreDataEnvir" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/CoreDataEnvir/CoreDataEnvir.framework/Headers" 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_LDFLAGS = $(inherited) -framework "CoreData" -framework "CoreDataEnvir" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_CoreDataEnvirSampleTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_CoreDataEnvirSampleTests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_CoreDataEnvirSampleTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_CoreDataEnvirSampleTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | PODS_BUILD_DIR = ${BUILD_DIR} 3 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 4 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 5 | PODS_ROOT = ${SRCROOT}/Pods 6 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_CoreDataEnvirSampleTests { 2 | umbrella header "Pods-CoreDataEnvirSampleTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-CoreDataEnvirSampleTests/Pods-CoreDataEnvirSampleTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 2 | PODS_BUILD_DIR = ${BUILD_DIR} 3 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 4 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 5 | PODS_ROOT = ${SRCROOT}/Pods 6 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CoreDataEnvir (since 2011-05-25) latest version 0.4 2 | ============= 3 | 4 | CoreDataEnvir is a CoreData wrapper which use CoreData in convient way and supply thread safe in concurrenct programming. You can use it concurrenctly,run seperate CoreDataEnvir instance on one thread. 5 | 6 | ## First step: 7 | 8 | Register your data base file name 9 | 10 | ```Objective-C 11 | [CoreDataEnvir registerDatabaseFileName:@"db.sqlite"]; 12 | ``` 13 | 14 | Register your model file name(no file extension name) 15 | 16 | ```Objective-C 17 | [CoreDataEnvir registerModelFileName:@"SampleModel"]; 18 | ``` 19 | 20 | ## Simple data base access: 21 | 22 | Let's assumption the `Book` class is a model which represent a book object in your reading app. It has some field are `name`, `author` ... etc. 23 | 24 | There is an author "John Stevens Cabot Abbott" written a book named "Napoleon Bonnaparte". 25 | 26 | ### Add new record 27 | 28 | ```Objective-C 29 | 30 | [Book insertItemWithFillingBlock:^(id item) { 31 | item.name = @"CoreData tutorial"; 32 | item.author = @"Headwindx"; 33 | }]; 34 | 35 | ``` 36 | 37 | ### Fetch lots of records 38 | 39 | ```Objective-C 40 | //Find all books of John Stevens Cabot Abbott. 41 | NSArray *books= [Feed itemsWithFormat:@"author = %@", @"John Stevens Cabot Abbott"]; 42 | 43 | ``` 44 | 45 | ### Fetch one record 46 | 47 | ```Objective-C 48 | //Find one book model object. 49 | Book *book = [Book lastItemWithFormat:@"name = %@ && author = %@", @"Napoleon Bonnaparte", @"John Stevens Cabot Abbott"]; 50 | 51 | ``` 52 | 53 | ### Delete one record 54 | 55 | ```Objective-C 56 | [CoreDataEnvir asyncMainInBlock:^(CoreDataEnvir *db) { 57 | [db deleteDataItem:book]; 58 | }]; 59 | 60 | ``` 61 | 62 | ### Delete records 63 | 64 | ```Objective-C 65 | [CoreDataEnvir asyncMainInBlock:^(CoreDataEnvir *db) { 66 | [db deleteDataItemSet:books]; 67 | }]; 68 | ``` 69 | 70 | ## Concurrenct programming: 71 | 72 | ### On main thread 73 | 74 | You can do some lightweight operation on main thread. All of above operation must runs on main thread by default or it will raise an exception by `CoreDataEnvir`. So you should be carefully. 75 | 76 | #### You also can explicit use on main thread 77 | 78 | It makes you feel more safe :-) 79 | 80 | ```Objective-C 81 | [CoreDataEnvir asyncMainInBlock:^(CoreDataEnvir *db) { 82 | [Book insertItemWithFillingBlock:^(id item) { 83 | item.name = @"CoreData tutorial"; 84 | item.author = @"Headwindx"; 85 | }]; 86 | }]; 87 | ``` 88 | 89 | ### On background thread 90 | 91 | It's already prepared a background GCD queue for you in `CoreDataEnvir`. 92 | 93 | The block `asyncBackgroundInBlock` will save memory cache to db file after `void(^)(CoreDataEnvir *db)` works finished. 94 | 95 | You don't need to use `[db saveDataBase];` like older version. 96 | 97 | ```Objective-C 98 | 99 | [CoreDataEnvir asyncBackgroundInBlock:^(CoreDataEnvir *db) { 100 | [Book insertItemOnBackgroundWithFillingBlock:^(id item) { 101 | item.name = @"CoreData tutorial"; 102 | item.author = @"Headwindx"; 103 | }]; 104 | }]; 105 | 106 | ``` 107 | 108 | It becomes more conveniently on concurrenct programming. 109 | 110 | ### Convenient methods 111 | 112 | Must run on main queue: 113 | 114 | 115 | * `+ (void)asyncMainInBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock;` 116 | * `+ (id)insertItemWithFillingBlock:(void(^)(id item))fillingBlock;` 117 | * `+ (NSArray *)itemsWithFormat:(NSString *)fmt,...;` 118 | ... 119 | 120 | Must run on background queue, you can use these APIs and some methods name within `Background`: 121 | 122 | * `+ (void)asyncBackgroundInBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock;` 123 | * `+ (id)insertItemOnBackgroundWithFillingBlock:(void(^)(id item))fillingBlock;` 124 | * `+ (NSArray *)itemsOnBackgroundWithFormat:(NSString *)fmt,...;` 125 | ... 126 | 127 | Or you wanna run some operation in your own dispatch queue, you can choose this APIs: 128 | 129 | * `+ (CoreDataEnvir *)createInstance;` you'd better hold this instance for future. 130 | * `- (void)asyncInBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock;` 131 | 132 | ## If your are newcomer to CoreData, please obey the rules below: 133 | 134 | * If you wanna keep you NSManagedObject objects, you shouldn't release you CoreDataEnvir object or it will be fault. 135 | 136 | * If you operate database in multiple threads, you should make sure you have one NSManagedObjectContext in seperate thread or GCD queue. Or it will occur conflict while one thread reading data and other one thread is writing data. 137 | 138 | > PS: So, in CoreDataEnvir please make sure your NSManagedObject object reference fetched from [CoreDataEnvir mainInstance] on main thread or from [CoreDataEnvir backgroundInstance] on background thread supplied by CoreDataEnvir and which never be released until application exist and it's enough for usual. 139 | 140 | 141 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/xudeheng/coredataenvir/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 142 | 143 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | CoreDataEnvir (since 2011-05-25) latest version 0.4 2 | ============= 3 | 4 | CoreDataEnvir 是一个 CoreData 框架的封装。提供了一种简单的方式来使用 CoreData ,它也为你的并发编程提供了线程安全支持。你可以在每个线程上运行一个单独的实例来进行并发编程。 5 | 6 | ## 第一步: 7 | 8 | 注册你的数据库文件名 9 | 10 | ```Objective-C 11 | [CoreDataEnvir registDatabaseFileName:@"db.sqlite"]; 12 | ``` 13 | 14 | 注册你的模型文件名(不包含文件扩展名) 15 | 16 | ```Objective-C 17 | [CoreDataEnvir registModelFileName:@"SampleModel"]; 18 | ``` 19 | 20 | ## 简单的数据库访问: 21 | 22 | 我们假设 `Book` 类是你的App中一个代表书籍对象的模型类。它有一些成员域 `name`, `author` 等等。 23 | 24 | 还有一个叫 "约翰史蒂芬" 的作者,写了一本传记叫 "拿破仑" 25 | 26 | ### 添加一个新记录 27 | 28 | ```Objective-C 29 | 30 | [Book insertItemWithFillingBlock:^(id item) { 31 | item.name = @"约翰史蒂芬"; 32 | item.author = @"拿破仑"; 33 | }]; 34 | 35 | ``` 36 | 37 | ### 查询一批记录 38 | 39 | ```Objective-C 40 | //查询 约翰史蒂芬 写得所有书籍 41 | NSArray *books= [Feed itemsWithFormat:@"author = %@", @"约翰史蒂芬"]; 42 | 43 | ``` 44 | 45 | ### 查询一条记录 46 | 47 | ```Objective-C 48 | //查找约翰史蒂芬写的拿破仑传记 49 | Book *book = [Book lastItemWithFormat:@"name = %@ && author = %@", @"拿破仑", @"约翰史蒂芬"]; 50 | 51 | ``` 52 | 53 | ### 删除一条记录 54 | 55 | ```Objective-C 56 | [CoreDataEnvir asyncMainInBlock:^(CoreDataEnvir *db) { 57 | [db deleteDataItem:book]; 58 | }]; 59 | 60 | ``` 61 | 62 | ### 删除多条记录 63 | 64 | ```Objective-C 65 | [CoreDataEnvir asyncMainInBlock:^(CoreDataEnvir *db) { 66 | [db deleteDataItemSet:books]; 67 | }]; 68 | ``` 69 | 70 | ## 并发编程: 71 | 72 | ### On main thread 73 | 74 | 你可以在主线程上做一些轻量级的操作,但最好不要影响到你的UI响应。所有以上介绍的数据操作,默认都是必须运行在主线程上的,否则 CoreDataEnvir 自己会主动抛出异常。所以你要注意这方面的使用,如果你不确定当前是否主线程,可以这么做: 75 | 76 | #### 你也可以明确地在主线程上使用 CoreDataEnvir 77 | 78 | 这样会让你感到比较有底一些: 79 | 80 | ```Objective-C 81 | [CoreDataEnvir asyncMainInBlock:^(CoreDataEnvir *db) { 82 | [Book insertItemWithFillingBlock:^(id item) { 83 | item.name = @"拿破仑"; 84 | item.author = @"约翰史蒂芬"; 85 | }]; 86 | }]; 87 | ``` 88 | 89 | ### 在后台线程 90 | 91 | CoreDataEnvir 也准备了一个后台 GCD 队列供你使用。 92 | 93 | Block `asyncBackgroundInBlock` 将会在 `void(^)(CoreDataEnvir *db)` 调用结束后,自动将变动保存到数据库中。 94 | 95 | 你不必像老版本一样直接调用 `[db saveDataBase];` 。 96 | 97 | ```Objective-C 98 | 99 | [CoreDataEnvir asyncBackgroundInBlock:^(CoreDataEnvir *db) { 100 | [Book insertItemOnBackgroundWithFillingBlock:^(id item) { 101 | item.name = @"拿破仑"; 102 | item.author = @"约翰史蒂芬"; 103 | }]; 104 | }]; 105 | 106 | ``` 107 | 108 | 这样在并发编程中 CoreData 的使用变得更加方便了。 109 | 110 | ### 几个快捷方法 111 | 112 | 必须在 GCD 主队列上运行: 113 | 114 | 115 | * `+ (void)asyncMainInBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock;` 116 | * `+ (id)insertItemWithFillingBlock:(void(^)(id item))fillingBlock;` 117 | * `+ (NSArray *)itemsWithFormat:(NSString *)fmt,...;` 118 | ... 119 | 120 | 必须在后台 GCD 队列上运行,你可以使用这些方法名称中包含 `Background` 的API: 121 | 122 | * `+ (void)asyncBackgroundInBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock;` 123 | * `+ (id)insertItemOnBackgroundWithFillingBlock:(void(^)(id item))fillingBlock;` 124 | * `+ (NSArray *)itemsOnBackgroundWithFormat:(NSString *)fmt,...;` 125 | ... 126 | 127 | 或者你想运行在你自己的 GCD 队列上,你可以选择这些 API: 128 | 129 | * `+ (CoreDataEnvir *)createInstance;` you'd better hold this instance for future. 130 | * `- (void)asyncInBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock;` 131 | 132 | ## 如果你是一个 CoreData 新人,请遵守以下军规: 133 | 134 | * 如果你想以后使用你的 NSManagedObject 对象,你不要释放 CoreDataEnvir 对象,否则模型对象都将失效。 135 | 136 | * 如果你想在多线程上操作数据库,一定要确保每个线程有自己独立的 NSManagedObjectContext 对象。 137 | 138 | > PS:在 CoreDataEnvir 中,请确保你的 NSManagedObject 对象是在主线程上从 [CoreDataEnvir mainInstance] 中获取的对象,或者在后台线程上从 [CoreDataEnvir backgroundInstance] 得到的对象。这两个对象是不会被释放的,通常情况下,CoreDataEnvir 提供的两个线程就能应付常见的并发情况了。 139 | -------------------------------------------------------------------------------- /Team+CoreDataClass.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Team+CoreDataClass.swift 3 | // 4 | // 5 | // Created by NicholasXu on 2020/9/14. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | import CoreDaaEnvir 12 | 13 | @objc(Team) 14 | public class Team: NSManagedObject { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /Team+CoreDataProperties.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Team+CoreDataProperties.swift 3 | // 4 | // 5 | // Created by NicholasXu on 2020/9/14. 6 | // 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | 12 | 13 | extension Team { 14 | 15 | @nonobjc public class func fetchRequest() -> NSFetchRequest { 16 | return NSFetchRequest(entityName: "Team") 17 | } 18 | 19 | @NSManaged public var name: String? 20 | @NSManaged public var number: NSNumber? 21 | @NSManaged public var members: NSSet? 22 | 23 | } 24 | 25 | // MARK: Generated accessors for members 26 | extension Team { 27 | 28 | @objc(addMembersObject:) 29 | @NSManaged public func addToMembers(_ value: Member) 30 | 31 | @objc(removeMembersObject:) 32 | @NSManaged public func removeFromMembers(_ value: Member) 33 | 34 | @objc(addMembers:) 35 | @NSManaged public func addToMembers(_ values: NSSet) 36 | 37 | @objc(removeMembers:) 38 | @NSManaged public func removeFromMembers(_ values: NSSet) 39 | 40 | } 41 | -------------------------------------------------------------------------------- /backup.sh: -------------------------------------------------------------------------------- 1 | git add --all 2 | git commit -m "update" 3 | git push local master && git push origin master 4 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | 2 | xcodebuild -scheme CoreDataEnvir -configuration Release -sdk iphonesimulator -arch i386 -arch x86_64 clean build CONFIGURATION_BUILD_DIR=./build/iphonesimulator 3 | xcodebuild -scheme CoreDataEnvir -configuration Release -sdk iphoneos clean build CONFIGURATION_BUILD_DIR=./build/iphoneos 4 | 5 | cp -rf ./build/iphonesimulator/CoreDataEnvir.framework ./build/CoreDataEnvir.framework 6 | 7 | lipo -create ./build/iphoneos/CoreDataEnvir.framework/CoreDataEnvir ./build/CoreDataEnvir.framework/CoreDataEnvir -o ./build/CoreDataEnvir.framework/CoreDataEnvir -------------------------------------------------------------------------------- /check: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | pod spec lint 3 | -------------------------------------------------------------------------------- /podupdate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #不检查 cocoapods 数据库,直接更新内部模块 3 | 4 | mode=$1 5 | 6 | if [ -z $mode ] 7 | then 8 | mode="update --no-repo-update" 9 | elif [ $mode == "u" ] 10 | then 11 | mode="update --no-repo-update" 12 | elif [ $mode == "i" ] 13 | then 14 | mode="install --no-repo-update" 15 | elif [ $mode == "c" ] 16 | then 17 | rm -rf *.xcworkspace 18 | rm -rf Pods/ 19 | rm Podfile.lock 20 | echo "Clear pod generated files." 21 | exit 0 22 | else 23 | echo "usage:" 24 | echo "./podupdate.sh i [\"for installing new libs\"]" 25 | echo "./podupdate.sh u [\"for updating exist libs\"]" 26 | exit 0 27 | fi 28 | 29 | echo $mode 30 | 31 | pod $mode 32 | -------------------------------------------------------------------------------- /push2pods: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | pod trunk push CoreDataEnvir.podspec --verbose 4 | -------------------------------------------------------------------------------- /pushtag: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | tagn=0.4 4 | 5 | xpush c "$1" && git push local --all && git tag -f "$tagn" && git push -f local "$tagn" 6 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvir.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir.h 3 | // CoreDataLab 4 | // 5 | // CoreData enviroment light wrapper. 6 | // Support CoreData operating methods. 7 | // 8 | // Create record item. 9 | // Support concurrency operating. 10 | // 11 | // Created by NicholasXu on 11-5-25. 12 | // 13 | // mailto:dehengxu@outlook.com 14 | // 15 | // Copyright 2011 NicholasXu. All rights reserved. 16 | // 17 | 18 | 19 | #import 20 | #import 21 | 22 | //#ifndef __CoreDataEnvir__ 23 | //#define __CoreDataEnvir__ 24 | 25 | #define CORE_DATA_ENVIR_SHOW_LOG 0 26 | 27 | @protocol CoreDataRescureDelegate; 28 | 29 | //! Project version number for CoreDataEnvir. 30 | FOUNDATION_EXPORT double CoreDataEnvirVersionNumber; 31 | 32 | //! Project version string for CoreDataEnvir. 33 | FOUNDATION_EXPORT const unsigned char CoreDataEnvirVersionString[]; 34 | 35 | NS_ASSUME_NONNULL_BEGIN 36 | 37 | #pragma mark - CoreDataEnvirement 38 | 39 | typedef enum 40 | { 41 | CDEErrorInstanceCreateTooMutch = 1000, 42 | CDEErrorModelFileNotFound = 1001 43 | }CoreDataEnvirError; 44 | 45 | extern NSString* const CDE_DOMAIN; 46 | 47 | @interface CoreDataEnvir : NSObject { 48 | NSRecursiveLock *__recursiveLock; 49 | } 50 | 51 | /// Current work queue 52 | #if OS_OBJECT_USE_OBJC 53 | @property (nonatomic, strong) dispatch_queue_t currentQueue; 54 | #else 55 | @property (nonatomic, assign) dispatch_queue_t currentQueue; 56 | #endif 57 | 58 | /** 59 | A model object. 60 | */ 61 | @property (nonatomic, readonly) NSManagedObjectModel *model; 62 | 63 | /** 64 | A context object. 65 | */ 66 | @property (nonatomic, readonly) NSManagedObjectContext *context; 67 | 68 | /** 69 | A persistance coordinator object. 70 | */ 71 | @property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator; 72 | 73 | /** 74 | A NSFetchedResultsController object, not be used by now. 75 | */ 76 | @property (nonatomic, strong) NSFetchedResultsController * fetchedResultsCtrl; 77 | 78 | /** 79 | Register resucrer, recommend using UIApplicationDelegate instance. 80 | */ 81 | @property (class, nonatomic, weak) id rescureDelegate; 82 | 83 | #pragma mark - Initialization 84 | 85 | /** 86 | Creating main instance if current thread is main thread else return an background instance. 87 | */ 88 | + (CoreDataEnvir *)instance; 89 | 90 | /** 91 | Creating a new instance by default db, momd file name. 92 | */ 93 | + (CoreDataEnvir *)createInstance; 94 | 95 | #pragma mark - Handle data store 96 | 97 | /** 98 | Save 99 | */ 100 | - (BOOL)saveDataBase; 101 | 102 | - (BOOL)saveForConfiguration:(NSString*)name; 103 | 104 | /** 105 | Operating on NSManagedObject 106 | */ 107 | - (id)dataItemWithID:(NSManagedObjectID *)objectId; 108 | - (id)updateDataItem:(NSManagedObject *)object; 109 | - (BOOL)deleteDataItem:(NSManagedObject *)aItem; 110 | - (BOOL)deleteDataItemSet:(NSSet *)aItemSet; 111 | - (BOOL)deleteDataItems:(NSArray*)items; 112 | 113 | #pragma mark - Observing context 114 | 115 | /** 116 | Add observing for concurrency. 117 | */ 118 | - (void)registerObserving; 119 | 120 | /** 121 | * Remove observer. 122 | */ 123 | - (void)unregisterObserving; 124 | 125 | 126 | #pragma mark - Work queue relevant 127 | 128 | /// run block asynchronously without saving context 129 | /// @param CoreDataBlock A block passing CoreDataEnvir instance 130 | - (void)asyncWithBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock; 131 | 132 | /// run block synchronously without saving context 133 | /// @param CoreDataBlock A block passing CoreDataEnvir instance 134 | - (void)syncWithBlock:(void(^)(CoreDataEnvir *db))CoreDataBlock; 135 | 136 | #pragma mark - NewAPIs initialization 137 | 138 | typedef void(^CoreDataEnvirBlock)(CoreDataEnvir* _Nonnull); 139 | 140 | /// Create instance with private work queue 141 | + (instancetype)create; 142 | 143 | /// Create instance and bind work queue with main queue 144 | + (instancetype)createMain; 145 | 146 | #pragma mark - NewAPIs setup CoreData requires 147 | 148 | /// Setup CoreData with reusable block 149 | /// @param config Block 150 | - (instancetype)setupWithBlock:(CoreDataEnvirBlock _Nonnull)config; 151 | 152 | /// Setup model and context 153 | /// @param fileURL model path 154 | - (instancetype)setupModelWithURL:(NSURL*)fileURL; 155 | 156 | /// Setup persistent with default configuration 157 | /// @param fileURL Store file path 158 | - (instancetype)setupDefaultPersistentStoreWithURL:(NSURL*)fileURL; 159 | 160 | /// Setup persistent for configuration 161 | /// @param fileURL Store file path 162 | /// @param name Configuration 163 | - (instancetype)setupPersistentStoreWithURL:(NSURL*)fileURL forConfiguration:(NSString* _Nullable)name; 164 | 165 | /// Return persistent store from persistent store coordinator 166 | /// @param fileURL Persistent store location 167 | - (NSPersistentStore*)persistentStoreForURL:(NSURL*)fileURL; 168 | 169 | /// Return persistent store from persistent store coordinator 170 | /// @param name Configuration 171 | - (NSPersistentStore*)persistentStoreForConfiguration:(NSString*)name; 172 | 173 | @end 174 | 175 | #pragma mark - NSPersistentStoreCoordinator 176 | 177 | @interface NSPersistentStoreCoordinator (CoreDataEnvir) 178 | 179 | /// Return persistent store from persistent store coordinator 180 | /// @param name Configuration 181 | - (NSPersistentStore *)persistentStoreForConfiguration:(NSString *)name; 182 | 183 | @end 184 | 185 | NS_ASSUME_NONNULL_END 186 | 187 | //#endif 188 | 189 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvir.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir.m 3 | // CoreDataLab 4 | // 5 | // Created by NicholasXu on 11-5-25. 6 | // Copyright 2011 NicholasXu. All rights reserved. 7 | // 8 | 9 | #import "CoreDataEnvir.h" 10 | 11 | #import "CoreDataEnvir_Private.h" 12 | #import "CoreDataEnvir_Main.h" 13 | #import "CoreDataEnvirObserver.h" 14 | #import "CoreDataRescureDelegate.h" 15 | #import "CoreDataEnvirDescriptor.h" 16 | 17 | // debug 18 | #if __has_include("NSManagedObject_Debug.h") 19 | #import "NSManagedObject_Debug.h" 20 | #import "NSObject_Debug.h" 21 | #endif 22 | 23 | // NSManagedObeject 24 | #import "NSManagedObject_Convenient.h" 25 | #import "NSManagedObject_MainThread.h" 26 | #import "NSManagedObject_Background.h" 27 | 28 | /** 29 | Do not use any lock method to protect thread resources in CoreData under concurrency condition! 30 | */ 31 | #define CONTEXT_LOCK_BEGIN do {\ 32 | BOOL _isLocked = [context tryLock];\ 33 | if (_isLocked) {\ 34 | 35 | #define CONTEXT_LOCK_END [context unlock];\ 36 | break;\ 37 | }\ 38 | } while(0); 39 | 40 | #define LOCK_BEGIN [recursiveLock lock]; 41 | #define LOCK_END [recursiveLock unlock]; 42 | 43 | NSString* const CDE_DOMAIN = @"com.dehengxu.CoreDataEnvir"; 44 | 45 | NSString* const kDEFAULT_CONFIGURATION_NAME = @"PF_DEFAULT_CONFIGURATION_NAME"; 46 | 47 | static NSString *_default_model_name = nil; 48 | static NSString *_default_model_dir = nil; 49 | static NSString *_default_db_dir = nil; 50 | static NSString *_default_db_file_name = nil; 51 | static dispatch_semaphore_t _sem_main = NULL; 52 | 53 | #pragma mark - CoreDataEnvir implementation 54 | 55 | @interface CoreDataEnvir () 56 | #pragma mark - rewrite property 57 | 58 | /// Current work queue 59 | //@property (nonatomic, strong) dispatch_queue_t currentQueue; 60 | 61 | /** 62 | A model object. 63 | */ 64 | @property (nonatomic, strong) NSManagedObjectModel *model; 65 | 66 | /** 67 | A context object. 68 | */ 69 | @property (nonatomic, strong) NSManagedObjectContext *context; 70 | 71 | @property (nonatomic, strong) NSMutableDictionary* persistentStoreCacheForName; 72 | 73 | @end 74 | 75 | @implementation CoreDataEnvir 76 | 77 | + (id)rescureDelegate { 78 | return _rescureDelegate; 79 | } 80 | 81 | + (void)setRescureDelegate:(id)rescureDelegate { 82 | _rescureDelegate = rescureDelegate; 83 | } 84 | 85 | #pragma mark - Initialization 86 | 87 | + (void)initialize 88 | { 89 | // Default db dir is document 90 | _default_db_dir = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] copy]; 91 | _default_db_file_name = @"db.sqlite"; 92 | _default_model_name = @"Model"; 93 | _sem_main = dispatch_semaphore_create(1l); 94 | } 95 | 96 | + (void)registerRescureDelegate:(id)delegate 97 | { 98 | _rescureDelegate = delegate; 99 | } 100 | 101 | #pragma mark - instance handle 102 | 103 | + (CoreDataEnvir *)instance 104 | { 105 | dispatch_semaphore_wait(_sem_main, ~0ull); 106 | CoreDataEnvir *db = nil; 107 | if ([[NSThread currentThread] isMainThread]) { 108 | db = [self mainInstance]; 109 | }else { 110 | db = [self createInstance]; 111 | } 112 | dispatch_semaphore_signal(_sem_main); 113 | 114 | return db; 115 | } 116 | 117 | + (CoreDataEnvir *)createInstance 118 | { 119 | CoreDataEnvir *cde = [CoreDataEnvirDescriptor.defaultInstance instance]; //[[self alloc] initWithDatabaseFileName:nil modelFileName:nil]; 120 | return cde; 121 | } 122 | 123 | - (instancetype)init { 124 | self = [super init]; 125 | if (self) { 126 | _create_counter ++; 127 | __recursiveLock = [[NSRecursiveLock alloc] init]; 128 | _persistentStoreCacheForName = @{}.mutableCopy; 129 | } 130 | return self; 131 | } 132 | 133 | - (void)dealloc { 134 | #if DEBUG && CORE_DATA_ENVIR_SHOW_LOG 135 | NSLog(@"%@", [self currentDispatchQueueLabel]); 136 | #endif 137 | _create_counter --; 138 | NSAssert(_create_counter >=0, @"over dealloc. %ld", _create_counter); 139 | #if DEBGU && CORE_DATA_ENVIR_SHOW_LOG 140 | NSLog(@"%s\ncreate counter :%d\n\n", __func__, _create_counter); 141 | #endif 142 | [self unregisterObserving]; 143 | } 144 | 145 | #pragma mark - Handle data store 146 | 147 | - (BOOL)saveDataBase 148 | { 149 | if (![self.context hasChanges]) { 150 | NSLog(@"Context no changed."); 151 | return YES; 152 | } 153 | __block BOOL bResult = NO; 154 | #pragma clang push 155 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 156 | 157 | void(^doWork)(void) = ^ { 158 | NSError *error = nil; 159 | bResult = [self.context save:&error]; 160 | 161 | if (!bResult) { 162 | if (error != nil) { 163 | NSLog(@"%s, %d, error:%@", __PRETTY_FUNCTION__, __LINE__, error); 164 | } 165 | //Do we need rollback? 166 | //[context rollback]; 167 | } 168 | }; 169 | 170 | if ([[UIDevice currentDevice] systemVersion].floatValue >= 8.0) { 171 | [self.persistentStoreCoordinator performBlockAndWait:doWork]; 172 | }else { 173 | [self.persistentStoreCoordinator lock]; 174 | doWork(); 175 | [self.persistentStoreCoordinator unlock]; 176 | } 177 | #pragma clang pop 178 | 179 | #if DEBGU && CORE_DATA_ENVIR_SHOW_LOG 180 | NSLog(@"%s", __FUNCTION__); 181 | #endif 182 | return bResult; 183 | } 184 | 185 | - (BOOL)saveForConfiguration:(NSString *)name { 186 | return NO; 187 | } 188 | 189 | #pragma mark - Data handling 190 | 191 | - (id)dataItemWithID:(NSManagedObjectID *)objectId 192 | { 193 | if (objectId && self.context) { 194 | 195 | NSManagedObject *item = nil; 196 | 197 | @try { 198 | item = [self.context objectWithID:objectId]; 199 | } 200 | @catch (NSException *exception) { 201 | NSLog(@"exce :%@", [exception description]); 202 | item = nil; 203 | } 204 | @finally { 205 | 206 | } 207 | 208 | return item; 209 | } 210 | return nil; 211 | } 212 | 213 | - (id)updateDataItem:(NSManagedObject *)object 214 | { 215 | if (object.isFault) { 216 | return [self dataItemWithID:object.objectID]; 217 | } 218 | return object; 219 | } 220 | 221 | - (BOOL)deleteDataItem:(NSManagedObject *)object 222 | { 223 | if (!object) { 224 | return NO; 225 | } 226 | 227 | NSManagedObject *getObject = object; 228 | if (object.isFault) { 229 | getObject = [self dataItemWithID:object.objectID]; 230 | } 231 | #if DEBUG && CORE_DATA_ENVIR_SHOW_LOG 232 | NSLog(@"%s objectID :%@; getObject :%@;", __FUNCTION__, aItem.objectID, getObject); 233 | #endif 234 | 235 | if (getObject) { 236 | @try { 237 | [self.context deleteObject:getObject]; 238 | } 239 | @catch (NSException *exception) { 240 | NSLog(@"Deleting abort cause exce :%@", [exception description]); 241 | return NO; 242 | } 243 | @finally { 244 | 245 | } 246 | } 247 | #if DEBUG && CORE_DATA_ENVIR_SHOW_LOG 248 | NSLog(@"delete finished!"); 249 | #endif 250 | 251 | return YES; 252 | } 253 | 254 | - (BOOL) deleteDataItemSet:(NSSet *)aItemSet 255 | { 256 | for (NSManagedObject *obj in aItemSet) { 257 | [self deleteDataItem:obj]; 258 | } 259 | 260 | return YES; 261 | } 262 | 263 | - (BOOL)deleteDataItems:(NSArray *)items 264 | { 265 | for (NSManagedObject *obj in items) { 266 | [self deleteDataItem:obj]; 267 | } 268 | 269 | return YES; 270 | } 271 | 272 | #pragma mark - Obseving context 273 | 274 | - (void)registerObserving 275 | { 276 | #if DEBUG 277 | NSLog(@"%s", __FUNCTION__); 278 | #endif 279 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:nil]; 280 | } 281 | 282 | - (void)unregisterObserving 283 | { 284 | #if DEBUG 285 | NSLog(@"%s", __FUNCTION__); 286 | #endif 287 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:nil]; 288 | } 289 | 290 | #pragma mark - Work queue relevant 291 | 292 | - (void)asyncWithBlock:(void (^)(CoreDataEnvir *))CoreDataBlock 293 | { 294 | dispatch_async([self currentQueue], ^{ 295 | CoreDataBlock(self); 296 | }); 297 | } 298 | 299 | - (void)syncWithBlock:(void (^)(CoreDataEnvir *)) CoreDataBlock 300 | { 301 | if ([NSThread isMainThread] && self.currentQueue == dispatch_get_main_queue()) { 302 | CoreDataBlock(self); 303 | }else { 304 | dispatch_sync([self currentQueue], ^{ 305 | CoreDataBlock(self); 306 | }); 307 | } 308 | } 309 | 310 | //+ (void)asyncMainInBlock:(void (^)(CoreDataEnvir *))CoreDataBlock 311 | //{ 312 | // [[self mainInstance] asyncInBlock:CoreDataBlock]; 313 | //} 314 | // 315 | //+ (void)asyncBackgroundInBlock:(void (^)(CoreDataEnvir *))CoreDataBlock 316 | //{ 317 | // [[self backgroundInstance] asyncInBlock:CoreDataBlock]; 318 | //} 319 | 320 | #pragma mark - NewAPIs 321 | 322 | + (instancetype)create { 323 | CoreDataEnvir* db = [CoreDataEnvir new]; 324 | db.currentQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@-%ld", [NSString stringWithUTF8String:"com.dehengxu.coredataenvir.background"], _create_counter] UTF8String], NULL); 325 | return db; 326 | } 327 | 328 | + (instancetype)createMain { 329 | CoreDataEnvir* db = [CoreDataEnvir new]; 330 | db.currentQueue = dispatch_get_main_queue(); 331 | return db; 332 | } 333 | 334 | 335 | #pragma mark - setup CoreData requires 336 | 337 | - (instancetype)setupWithBlock:(void (^)(CoreDataEnvir * _Nonnull))config { 338 | [self syncWithBlock:config]; 339 | return self; 340 | } 341 | 342 | - (instancetype)setupModelWithURL:(NSURL *)fileURL { 343 | NSAssert(fileURL, @"fileURL must be non-null."); 344 | NSAssert(fileURL.isFileURL, @"fileURL must begin with file://"); 345 | if (!fileURL || !fileURL.isFileURL) { 346 | return nil; 347 | } 348 | 349 | NSLog(@"model %d, url: %@", fileURL.isFileURL, fileURL.path); 350 | if (![NSFileManager.defaultManager fileExistsAtPath:fileURL.path isDirectory:NULL]) { 351 | NSAssert(false, @"fileURL does not exist: %@", fileURL.absoluteString); 352 | return nil; 353 | } 354 | 355 | self.model = [[NSManagedObjectModel alloc] initWithContentsOfURL:fileURL]; 356 | if (!_context) { 357 | _context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 358 | } 359 | [self.context setRetainsRegisteredObjects:NO]; 360 | [self.context setPropagatesDeletesAtEndOfEvent:NO]; 361 | [self.context setMergePolicy:NSOverwriteMergePolicy]; 362 | 363 | return self; 364 | } 365 | 366 | - (instancetype)setupDefaultPersistentStoreWithURL:(NSURL *)fileURL { 367 | if (!self.model) { 368 | NSAssert(false, @"Should initialize model prior"); 369 | return nil; 370 | } 371 | 372 | if (!_persistentStoreCoordinator) { 373 | self.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model]; 374 | } 375 | if (!self.persistentStoreCoordinator) { 376 | NSAssert(false, @"Create persistentStoreCoordinator failed"); 377 | return nil; 378 | } 379 | [self.context setPersistentStoreCoordinator:self.persistentStoreCoordinator]; 380 | 381 | [self registerObserving]; 382 | 383 | if (![self setupPersistentStoreWithURL:fileURL forConfiguration:nil]) { 384 | return nil; 385 | } 386 | 387 | return self; 388 | } 389 | 390 | - (instancetype)setupPersistentStoreWithURL:(NSURL *)fileURL forConfiguration:(NSString *_Nullable)name { 391 | 392 | NSError* error = nil; 393 | [self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:name URL:fileURL options:[self defaultPersistentOptions] error:&error]; 394 | if (error) { 395 | NSAssert(error, @"Add persistent store failed: %@", error); 396 | return nil; 397 | } 398 | NSLog(@"Add persistent store %@ to %@", name, fileURL); 399 | 400 | return self; 401 | } 402 | 403 | - (NSPersistentStore *)persistentStoreForURL:(NSURL *)fileURL { 404 | return [_persistentStoreCoordinator persistentStoreForURL:fileURL]; 405 | } 406 | 407 | - (NSPersistentStore *)persistentStoreForConfiguration:(NSString *)name { 408 | id store = _persistentStoreCacheForName[name]; 409 | if (store) { return store; } 410 | store = [_persistentStoreCoordinator persistentStoreForConfiguration:name]; 411 | _persistentStoreCacheForName[name] = store; // over write cache 412 | return store; 413 | } 414 | 415 | 416 | @end 417 | 418 | #pragma mark - NSPersistentStoreCoordinator 419 | 420 | @implementation NSPersistentStoreCoordinator (CoreDataEnvir) 421 | 422 | - (NSPersistentStore *)persistentStoreForConfiguration:(NSString *)name { 423 | for (NSPersistentStore* persi in self.persistentStores) { 424 | if ([persi.configurationName isEqualToString:name]) { 425 | return persi; 426 | } 427 | } 428 | return nil; 429 | } 430 | 431 | @end 432 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvirDescriptor.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvirDescriptor.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng Xu on 2020/9/19. 6 | // Copyright © 2020 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @class CoreDataEnvir; 14 | 15 | @interface CoreDataEnvirDescriptor : NSObject 16 | 17 | @property (class, nonatomic, readonly) CoreDataEnvirDescriptor* defaultInstance; 18 | 19 | @property (nonatomic, copy, nullable) NSString* modelName; 20 | @property (nonatomic, copy) NSString* storeFileName; 21 | @property (nonatomic, copy) NSString* storeDirectory; 22 | @property (nonatomic, copy, nullable) NSArray* storeURLs; 23 | @property (nonatomic, copy, nullable) NSArray* configurations; 24 | @property (nonatomic, strong) NSBundle* bundle; 25 | 26 | + (instancetype)instance; 27 | 28 | + (instancetype)instanceWithModelName:(NSString* _Nullable)modelName bundle:(NSBundle* _Nullable)bundle storeFileName:(NSString* _Nullable)fileName storedUnderDirectory:(NSString* _Nullable)directory; 29 | 30 | //- (instancetype) NS_DESIGNATED_INITIALIZER init; 31 | 32 | - (instancetype) NS_DESIGNATED_INITIALIZER initWithModelName:(NSString* _Nullable)modelName bundle:(NSBundle* _Nullable)bundle storeFileName:(NSString* _Nullable)fileName storedUnderDirectory:(NSString* _Nullable)directory; 33 | 34 | - (CoreDataEnvir*)mainInstance; 35 | - (CoreDataEnvir*)backgroundInstance; 36 | - (CoreDataEnvir*)instance; 37 | 38 | @end 39 | 40 | NS_ASSUME_NONNULL_END 41 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvirDescriptor.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvirDescriptor.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by Deheng Xu on 2020/9/19. 6 | // Copyright © 2020 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "CoreDataEnvirDescriptor.h" 10 | #import "CoreDataEnvir.h" 11 | #import "CoreDataEnvir_Private.h" 12 | 13 | @interface CoreDataEnvirDescriptor () 14 | @end 15 | 16 | @implementation CoreDataEnvirDescriptor 17 | 18 | + (instancetype)defaultInstance { 19 | static dispatch_once_t onceToken = 0; 20 | static CoreDataEnvirDescriptor* __shared__ = nil; 21 | dispatch_once(&onceToken, ^{ 22 | __shared__ = [[super alloc] init]; 23 | __shared__.modelName = nil;//@"Model"; 24 | __shared__.storeFileName = @"db.sqlite"; 25 | __shared__.storeDirectory = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] copy]; 26 | __shared__.bundle = NSBundle.mainBundle; 27 | }); 28 | return __shared__; 29 | } 30 | 31 | + (instancetype)instance { 32 | return [self instanceWithModelName:nil bundle:nil storeFileName:nil storedUnderDirectory:nil]; 33 | } 34 | 35 | + (instancetype)instanceWithModelName:(NSString *)modelName bundle:(NSBundle *)bundle storeFileName:(NSString *)fileName storedUnderDirectory:(NSString *)directory { 36 | CoreDataEnvirDescriptor* ins = [[CoreDataEnvirDescriptor alloc] initWithModelName:modelName bundle:bundle storeFileName:fileName storedUnderDirectory:directory]; 37 | return ins; 38 | } 39 | 40 | - (instancetype)initWithModelName:(NSString *)modelName bundle:(NSBundle *)bundle storeFileName:(NSString *)fileName storedUnderDirectory:(NSString *)directory { 41 | self = [super init]; 42 | if (self) { 43 | self.modelName = modelName ?: [self.class.defaultInstance modelName]; 44 | self.storeFileName = fileName ?: self.class.defaultInstance.storeFileName; 45 | self.storeDirectory = directory ?: self.class.defaultInstance.storeDirectory; 46 | self.bundle = bundle ?: self.class.defaultInstance.bundle; 47 | } 48 | return self; 49 | } 50 | 51 | - (NSURL*)modelURL { 52 | NSURL* url = [self.bundle URLForResource:self.modelName withExtension:@"momd"]; 53 | return url; 54 | } 55 | 56 | - (NSURL*)storeURL { 57 | NSURL* url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", self.storeDirectory, self.storeFileName]]; 58 | return url; 59 | } 60 | 61 | - (CoreDataEnvir *)mainInstance { 62 | 63 | static dispatch_once_t onceToken; 64 | dispatch_once(&onceToken, ^{ 65 | _mainInstance = [self generate]; 66 | _mainInstance.currentQueue = dispatch_get_main_queue(); 67 | }); 68 | 69 | return _mainInstance; 70 | } 71 | 72 | - (CoreDataEnvir *)backgroundInstance { 73 | 74 | static dispatch_once_t onceToken; 75 | dispatch_once(&onceToken, ^{ 76 | _backgroundInstance = [self instance]; 77 | }); 78 | 79 | return _backgroundInstance; 80 | } 81 | 82 | - (CoreDataEnvir*)generate { 83 | CoreDataEnvir* ins = [CoreDataEnvir new]; 84 | [ins setupModelWithURL:[self modelURL]]; 85 | [ins setupDefaultPersistentStoreWithURL:[self storeURL]]; 86 | for (int i = 0; i < self.configurations.count; i++) { 87 | NSString* name = self.configurations[i]; 88 | NSURL* url = [self storeURL]; 89 | 90 | if (self.storeURLs.count) { 91 | url = [self.storeURLs objectAtIndex:i]; 92 | } 93 | 94 | [ins setupPersistentStoreWithURL:url forConfiguration:name]; 95 | } 96 | return ins; 97 | } 98 | 99 | - (CoreDataEnvir *)instance { 100 | CoreDataEnvir* ins = [self generate]; 101 | if (ins && ![ins currentQueue] ) { 102 | ins.currentQueue = dispatch_queue_create([[NSString stringWithFormat:@"%@-%ld", [NSString stringWithUTF8String:"com.dehengxu.coredataenvir.background"], _create_counter] UTF8String], NULL); 103 | } 104 | return ins; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvirHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvirHeader.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #ifndef CoreDataEnvir_CoreDataEnvirHeader_h 10 | #define CoreDataEnvir_CoreDataEnvirHeader_h 11 | 12 | #import 13 | #import 14 | #import 15 | #import 16 | 17 | #import 18 | #import 19 | #import 20 | 21 | //! Project version number for CoreDataEnvir. 22 | FOUNDATION_EXPORT double CoreDataEnvirVersionNumber; 23 | 24 | //! Project version string for CoreDataEnvir. 25 | FOUNDATION_EXPORT const unsigned char CoreDataEnvirVersionString[]; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvirObserver.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvirObserver.h 3 | // CoreDataEnvirFramework 4 | // 5 | // Created by Deheng Xu on 2020/9/18. 6 | // Copyright © 2020 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | #pragma mark - CoreDataEnvirObserver (Not be used temporarily) 14 | 15 | @protocol CoreDataEnvirObserver 16 | 17 | @optional 18 | - (void)didFetchingFinished:(NSArray *) aItems; 19 | - (void)didUpdateContext:(id)sender; 20 | - (void)didDeleteObjects:(id)sender; 21 | - (void)didInsertObjects:(id)sender; 22 | - (void)didUpdateObjects:(id)sender; 23 | 24 | @end 25 | 26 | 27 | 28 | NS_ASSUME_NONNULL_END 29 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvir_Background.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir_Background.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface CoreDataEnvir (CDEBackground) 15 | 16 | + (CoreDataEnvir *)backgroundInstance; 17 | 18 | + (dispatch_queue_t)backgroundQueue; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvir_Background.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir_Background.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "CoreDataEnvir_Background.h" 10 | #import "CoreDataEnvirDescriptor.h" 11 | 12 | @implementation CoreDataEnvir (CDEBackground) 13 | 14 | + (CoreDataEnvir *)backgroundInstance 15 | { 16 | return [CoreDataEnvirDescriptor.defaultInstance backgroundInstance]; 17 | } 18 | 19 | + (dispatch_queue_t)backgroundQueue 20 | { 21 | return [[CoreDataEnvir backgroundInstance] currentQueue]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvir_Main.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir_Main.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/31. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface CoreDataEnvir (CDEMain) 16 | 17 | /** 18 | Only returen a single instance runs on main thread. 19 | */ 20 | + (CoreDataEnvir *)mainInstance; 21 | 22 | /** 23 | Main queue. 24 | */ 25 | + (dispatch_queue_t)mainQueue; 26 | 27 | @end 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataEnvir_Main.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir_Main.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/31. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "CoreDataEnvir_Main.h" 10 | #import "CoreDataEnvirDescriptor.h" 11 | 12 | @implementation CoreDataEnvir (CDEMain) 13 | 14 | + (CoreDataEnvir *)mainInstance 15 | { 16 | return [CoreDataEnvirDescriptor.defaultInstance mainInstance]; 17 | } 18 | 19 | + (dispatch_queue_t)mainQueue 20 | { 21 | return [[CoreDataEnvir mainInstance] currentQueue]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/CoreDataRescureDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataRescureDelegate.h 3 | // CoreDataEnvirFramework 4 | // 5 | // Created by Deheng Xu on 2020/9/18. 6 | // Copyright © 2020 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @class CoreDataEnvir; 14 | 15 | #pragma mark - CoreDataRescureDelegate 16 | 17 | /** 18 | CoreData rescure delegate. 19 | While core data envirement init fails occured. 20 | */ 21 | @protocol CoreDataRescureDelegate 22 | 23 | @optional 24 | 25 | /** 26 | Reture if need rescure or abort directly. 27 | */ 28 | - (BOOL)shouldRescureCoreData; 29 | 30 | /** 31 | Return if abort while rescure failed. 32 | */ 33 | - (BOOL)shouldAbortWhileRescureFailed; 34 | 35 | /** 36 | Did start rescure core data. 37 | 38 | @param cde A CoreDataEnvir instance. 39 | */ 40 | - (void)didStartRescureCoreData:(CoreDataEnvir *)cde; 41 | 42 | /** 43 | Did finished rescuring work. 44 | 45 | @param cde A CoreDataEnvir instance. 46 | */ 47 | - (void)didFinishedRescuringCoreData:(CoreDataEnvir *)cde; 48 | 49 | /** 50 | Rescure failed. 51 | 52 | @param cde A CoreDataEnvir instance. 53 | */ 54 | - (void)rescureFailed:(CoreDataEnvir *)cde; 55 | 56 | @end 57 | 58 | 59 | 60 | NS_ASSUME_NONNULL_END 61 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/ManagedObject/NSManagedObject_Background.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSManagedObject_Background.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NSManagedObject (CDEBackground) 15 | 16 | /** 17 | Creating managed object on main thread. 18 | */ 19 | + (instancetype)insertItemOnBackground; 20 | 21 | /** 22 | Creating managed object in main context by filling 'block' 23 | */ 24 | + (instancetype)insertItemOnBackgroundWithFillingBlock:(void(^)(NSManagedObject* item))fillingBlock; 25 | 26 | /** 27 | Just fetching record items by the predicate in main context. 28 | */ 29 | + (NSArray *)itemsOnBackground; 30 | 31 | /** 32 | Fetch record items in main context by predicate. 33 | */ 34 | + (NSArray *)itemsOnBackgroundWithPredicate:(NSPredicate *)predicate; 35 | 36 | /** 37 | Fetch record items in main context by formated string. 38 | */ 39 | + (NSArray *)itemsOnBackgroundWithFormat:(NSString *)fmt,...; 40 | 41 | /** 42 | * Fetch record items in main context by predicate format string more simpler. 43 | * 44 | * @param sortDescriptions SortDescriptions 45 | * @param fmt Predicate format string. 46 | * 47 | * @return Array of items match the condition. 48 | */ 49 | + (NSArray *)itemsOnBackgroundSortDescriptions:(NSArray *)sortDescriptions withFormat:(NSString *)fmt,...; 50 | 51 | /** 52 | * Fetch record items in main context by predicate format string more simpler. 53 | * 54 | * @param sortDescriptions SortDescriptions 55 | * @param offset offset 56 | * @param limitNumber limit number 57 | * @param fmt predicate format string. 58 | * 59 | * @return Array of items match the condition. 60 | */ 61 | + (NSArray *)itemsOnBackgroundSortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber withFormat:(NSString *)fmt,...; 62 | 63 | /** 64 | * Fetching last record item. 65 | */ 66 | + (instancetype)lastItemOnBackground; 67 | 68 | /** 69 | * Fetch record item by predicate in main context. 70 | * 71 | * @param predicate Predicate object.s 72 | * 73 | * @return Last item of the managed object in context. 74 | */ 75 | + (instancetype)lastItemOnBackgroundWithPredicate:(NSPredicate *)predicate; 76 | 77 | /** 78 | 79 | */ 80 | /** 81 | * Fetch record item by formated string in main context. 82 | * 83 | * @param fmt Predicate format. 84 | * 85 | * @return Last item of the managed object in context. 86 | */ 87 | + (instancetype)lastItemOnBackgroundWithFormat:(NSString *)fmt,...; 88 | 89 | @end 90 | 91 | NS_ASSUME_NONNULL_END 92 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/ManagedObject/NSManagedObject_Background.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSManagedObject_Background.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "NSManagedObject_Background.h" 10 | #import "CoreDataEnvir_Background.h" 11 | #import "CoreDataEnvir_Private.h" 12 | #import "NSManagedObject_Convenient.h" 13 | 14 | @implementation NSManagedObject (CDEBackground) 15 | 16 | /** 17 | * Insert an item. 18 | */ 19 | + (instancetype)insertItemOnBackground 20 | { 21 | CoreDataEnvir *db = [CoreDataEnvir backgroundInstance]; 22 | id item = nil; 23 | item = [self insertItemInContext:db]; 24 | return item; 25 | } 26 | 27 | /** 28 | * Insert an item by block 29 | * 30 | * @param fillingBlock Fill data with this block 31 | * 32 | * @return NSManagedObject 33 | */ 34 | + (instancetype)insertItemOnBackgroundWithFillingBlock:(void (^)(id item))fillingBlock 35 | { 36 | CoreDataEnvir* db = [CoreDataEnvir backgroundInstance]; 37 | [db asyncWithBlock:^(CoreDataEnvir * _Nonnull db) { 38 | [self insertItemInContext:db fillData:fillingBlock]; 39 | [db saveDataBase]; 40 | }]; 41 | return nil; 42 | } 43 | 44 | + (NSArray *)itemsOnBackground 45 | { 46 | CoreDataEnvir *db = [CoreDataEnvir backgroundInstance]; 47 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self)]; 48 | 49 | return items; 50 | } 51 | 52 | + (NSArray *)itemsOnBackgroundWithPredicate:(NSPredicate *)predicate 53 | { 54 | CoreDataEnvir *db = [CoreDataEnvir backgroundInstance]; 55 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:predicate]; 56 | return items; 57 | } 58 | 59 | + (NSArray *)itemsOnBackgroundWithFormat:(NSString *)fmt, ... 60 | { 61 | va_list args; 62 | va_start(args, fmt); 63 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 64 | va_end(args); 65 | CoreDataEnvir *db = [CoreDataEnvir backgroundInstance]; 66 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred]; 67 | return items; 68 | } 69 | 70 | + (NSArray *)itemsOnBackgroundSortDescriptions:(NSArray *)sortDescriptions withFormat:(NSString *)fmt, ... 71 | { 72 | va_list args; 73 | va_start(args, fmt); 74 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 75 | va_end(args); 76 | CoreDataEnvir *db = [CoreDataEnvir backgroundInstance]; 77 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred usingSortDescriptions:sortDescriptions]; 78 | return items; 79 | } 80 | 81 | + (NSArray *)itemsOnBackgroundSortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber withFormat:(NSString *)fmt, ... 82 | { 83 | va_list args; 84 | va_start(args, fmt); 85 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 86 | va_end(args); 87 | CoreDataEnvir *db = [CoreDataEnvir backgroundInstance]; 88 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred usingSortDescriptions:sortDescriptions fromOffset:offset LimitedBy:limitNumber]; 89 | return items; 90 | } 91 | 92 | + (instancetype)lastItemOnBackground 93 | { 94 | return [[self itemsOnBackground] lastObject]; 95 | } 96 | 97 | + (instancetype)lastItemOnBackgroundWithPredicate:(NSPredicate *)predicate 98 | { 99 | return [[self itemsInContext:[CoreDataEnvir backgroundInstance] usingPredicate:predicate] lastObject]; 100 | } 101 | 102 | + (instancetype)lastItemOnBackgroundWithFormat:(NSString *)fmt, ... 103 | { 104 | va_list args; 105 | va_start(args, fmt); 106 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 107 | va_end(args); 108 | return [self lastItemOnBackgroundWithPredicate:pred]; 109 | } 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/ManagedObject/NSManagedObject_Convenient.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSManagedObject_Convient.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NSManagedObject (CDEConevient) 15 | 16 | + (NSUInteger)totalCountInContext:(CoreDataEnvir*)db forConfiguration:(NSString* _Nullable)name; 17 | 18 | #pragma mark - Inserting operations. 19 | 20 | + (NSFetchRequest*)newFetchRequestInContext:(CoreDataEnvir*)db; 21 | 22 | /** 23 | Creating managed object on background thread. 24 | */ 25 | + (instancetype)insertItemInContext:(CoreDataEnvir *)cde; 26 | 27 | /** 28 | Createing managed object in specified context with filling 'block' 29 | */ 30 | + (instancetype)insertItemInContext:(CoreDataEnvir *)cde fillData:(void (^)(NSManagedObject* item))fillingBlock; 31 | 32 | #pragma mark - Fetching operations. 33 | 34 | /** 35 | Fetching record items in specified context. 36 | */ 37 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde; 38 | 39 | /** 40 | Fetch record items by predicate. 41 | */ 42 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde usingPredicate:(NSPredicate *)predicate; 43 | 44 | /** 45 | Fetch record items by format string. 46 | */ 47 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde withFormat:(NSString *)fmt,...; 48 | 49 | /** 50 | * Fetch items by sort descriptions. 51 | * 52 | * @param cde CoreDataEnvir instance. 53 | * @param sortDescriptions SortDescriptions 54 | * @param fmt Predicate format. 55 | * 56 | * @return Array of items match the condition. 57 | */ 58 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde sortDescriptions:(NSArray *)sortDescriptions withFormat:(NSString *)fmt,...; 59 | 60 | /** 61 | * Fetch items addition by limited range. 62 | * 63 | * @param cde CoreDataEnvir instance 64 | * @param sortDescriptions SortDescriptions 65 | * @param offset offset 66 | * @param limitNumber limted number 67 | * @param fmt Predicate format. 68 | * 69 | * @return Array of items match the condition. 70 | */ 71 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde sortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber withFormat:(NSString *)fmt,...; 72 | 73 | /** 74 | * Fetch item in specified context. 75 | * 76 | * @param cde CoreDataEnvir instance 77 | * 78 | * @return Last item of the managed object in context. 79 | */ 80 | + (instancetype)lastItemInContext:(CoreDataEnvir *)cde; 81 | 82 | /** 83 | * Fetch item in specified context through predicate. 84 | * 85 | * @param cde CoreDataEnvir instance 86 | * @param predicate Predicate. 87 | * 88 | * @return Last item of the managed object in context. 89 | */ 90 | + (instancetype)lastItemInContext:(CoreDataEnvir *)cde usingPredicate:(NSPredicate *)predicate; 91 | 92 | /** 93 | * Fetch item in specified context through format string. 94 | * 95 | * @param cde CoreDataEnvir object. 96 | * @param fmt Predicate format string. 97 | * 98 | * @return Last item of the managed object in context. 99 | */ 100 | + (instancetype)lastItemInContext:(CoreDataEnvir *)cde withFormat:(NSString *)fmt,...; 101 | 102 | #pragma mark - fault process. 103 | 104 | /** 105 | * Update NSManagedObject if faulted. 106 | * 107 | * @return Updated object. 108 | */ 109 | - (instancetype)update; 110 | 111 | /** 112 | Update NSManagedObject in specified context if faulted. 113 | 114 | @param cde CoreDataEnvir object. 115 | */ 116 | - (instancetype)updateInContext:(CoreDataEnvir *)cde; 117 | 118 | #pragma mark - Deleting . 119 | 120 | /** 121 | * Remove item. 122 | * 123 | * @param cde CoreDataEnvir object. 124 | */ 125 | - (void)removeFrom:(CoreDataEnvir *)cde; 126 | 127 | /** 128 | * Remove item. 129 | */ 130 | - (void)remove; 131 | 132 | #pragma mark - Drive to save. 133 | 134 | /** 135 | * Save db on main thread. 136 | * 137 | * @param cde CoreDataEnvir object. 138 | * 139 | * @return Success(YES) or failed(NO). 140 | */ 141 | - (BOOL)saveTo:(CoreDataEnvir *)cde; 142 | 143 | /** 144 | Save db on main thread. 145 | */ 146 | - (BOOL)save; 147 | 148 | /** 149 | * Save db on main thread. 150 | * 151 | * @param cde CoreDataEnvir object. 152 | * 153 | * @return Success(YES) or failed(NO). 154 | */ 155 | - (BOOL)saveTo:(CoreDataEnvir *)cde forConfiguration:(NSString*)name; 156 | 157 | @end 158 | 159 | NS_ASSUME_NONNULL_END 160 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/ManagedObject/NSManagedObject_Convenient.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSManagedObject_Convient.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "NSManagedObject_Convenient.h" 10 | #import "CoreDataEnvir_Private.h" 11 | #import "CoreDataEnvir_Main.h" 12 | #import "CoreDataEnvir_Background.h" 13 | 14 | @implementation NSManagedObject (CDEConevient) 15 | 16 | + (NSUInteger)totalCountInContext:(CoreDataEnvir *)db forConfiguration:(NSString *)name { 17 | NSFetchRequest* req = [self newFetchRequestInContext:db]; 18 | if (name.length) { 19 | NSPersistentStore* store = [db persistentStoreForConfiguration:name]; 20 | req.affectedStores = @[store]; 21 | } 22 | return [db countForFetchRequest:req error:nil]; 23 | } 24 | 25 | + (NSFetchRequest*)newFetchRequestInContext:(CoreDataEnvir*)db { 26 | NSFetchRequest *req = [[NSFetchRequest alloc] init]; 27 | NSString* name = NSStringFromClass(self.class); 28 | NSAssert(name.length, @"class name not found."); 29 | NSEntityDescription *entity = [NSEntityDescription entityForName:name inManagedObjectContext:db.context]; 30 | [req setEntity:entity]; 31 | return req; 32 | } 33 | 34 | #pragma mark - Insert item record 35 | 36 | + (instancetype)insertItemInContext:(CoreDataEnvir *)cde 37 | { 38 | id item = nil; 39 | NSError* err = nil; 40 | item = [cde buildManagedObjectByClass:self error:&err]; 41 | return item; 42 | } 43 | 44 | + (instancetype)insertItemInContext:(CoreDataEnvir *)cde fillData:(void (^)(id item))fillingBlock 45 | { 46 | id item = [self insertItemInContext:cde]; 47 | fillingBlock(item); 48 | return item; 49 | } 50 | 51 | #pragma mark - fetch items 52 | 53 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde 54 | { 55 | NSArray *items = [cde fetchItemsByEntityDescriptionName:NSStringFromClass(self)]; 56 | return items; 57 | } 58 | 59 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde usingPredicate:(NSPredicate *)predicate 60 | { 61 | NSArray *items = [cde fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:predicate]; 62 | return items; 63 | } 64 | 65 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde withFormat:(NSString *)fmt, ... 66 | { 67 | va_list args; 68 | va_start(args, fmt); 69 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 70 | va_end(args); 71 | 72 | NSArray *items = [cde fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred]; 73 | return items; 74 | } 75 | 76 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde sortDescriptions:(NSArray *)sortDescriptions withFormat:(NSString *)fmt, ... 77 | { 78 | va_list args; 79 | va_start(args, fmt); 80 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 81 | va_end(args); 82 | NSArray *items = [cde fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred usingSortDescriptions:sortDescriptions]; 83 | return items; 84 | } 85 | 86 | + (NSArray *)itemsInContext:(CoreDataEnvir *)cde sortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber withFormat:(NSString *)fmt, ... 87 | { 88 | va_list args; 89 | va_start(args, fmt); 90 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 91 | va_end(args); 92 | NSArray *items = [cde fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred usingSortDescriptions:sortDescriptions fromOffset:offset LimitedBy:limitNumber]; 93 | return items; 94 | } 95 | 96 | #pragma mark - fetch last item 97 | 98 | + (instancetype)lastItemInContext:(CoreDataEnvir *)cde 99 | { 100 | return [[self itemsInContext:cde] lastObject]; 101 | } 102 | 103 | + (instancetype)lastItemInContext:(CoreDataEnvir *)cde usingPredicate:(NSPredicate *)predicate 104 | { 105 | return [[self itemsInContext:cde usingPredicate:predicate] lastObject]; 106 | } 107 | 108 | + (instancetype)lastItemInContext:(CoreDataEnvir *)cde withFormat:(NSString *)fmt, ... 109 | { 110 | va_list args; 111 | va_start(args, fmt); 112 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 113 | va_end(args); 114 | 115 | return [[self itemsInContext:cde usingPredicate:pred] lastObject]; 116 | } 117 | 118 | #pragma mark - merge context when update 119 | 120 | - (instancetype)update 121 | { 122 | if ([NSThread isMainThread]) { 123 | return [[CoreDataEnvir instance] updateDataItem:self]; 124 | } 125 | return nil; 126 | } 127 | 128 | - (instancetype)updateInContext:(CoreDataEnvir *)cde 129 | { 130 | return [cde updateDataItem:self]; 131 | } 132 | 133 | - (void)removeFrom:(CoreDataEnvir *)cde 134 | { 135 | if (!cde) { 136 | return; 137 | } 138 | [cde deleteDataItem:self]; 139 | } 140 | 141 | - (void)remove 142 | { 143 | if (![NSThread isMainThread]) { 144 | #if DEBUG 145 | NSLog(@"Remove data failed, cannot run on non-main thread!"); 146 | #endif 147 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Remove data failed, must run on main thread!" userInfo:nil] raise]; 148 | return; 149 | } 150 | if (![CoreDataEnvir mainInstance]) { 151 | return; 152 | } 153 | [[CoreDataEnvir mainInstance] deleteDataItem:self]; 154 | } 155 | 156 | - (BOOL)saveTo:(CoreDataEnvir *)cde 157 | { 158 | if (!cde) { 159 | return NO; 160 | } 161 | 162 | return [cde saveDataBase]; 163 | } 164 | 165 | - (BOOL)save 166 | { 167 | if (![NSThread isMainThread]) { 168 | #if DEBUG 169 | NSLog(@"Save data failed, cannot run on non-main thread!"); 170 | #endif 171 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Save data failed, must run on main thread!" userInfo:nil] raise]; 172 | return NO; 173 | } 174 | if (![CoreDataEnvir mainInstance]) { 175 | return NO; 176 | } 177 | 178 | return [[CoreDataEnvir mainInstance] saveDataBase]; 179 | } 180 | 181 | - (BOOL)saveTo:(CoreDataEnvir *)cde forConfiguration:(NSString *)name { 182 | NSPersistentStore* store = [cde persistentStoreForConfiguration:name]; 183 | [cde.context assignObject:self toPersistentStore:store]; 184 | [cde saveDataBase]; 185 | return NO; 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/ManagedObject/NSManagedObject_MainThread.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSManagedObject_MainThread.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NSManagedObject (CDEMainThread) 15 | 16 | #pragma mark - Inserting operations. 17 | 18 | /** 19 | Creating managed object on main thread. 20 | */ 21 | + (instancetype)insertItem; 22 | 23 | /** 24 | Creating managed object in main context by filling 'block' 25 | */ 26 | + (instancetype _Nullable)insertItemWithFillingBlock:(void(^)(NSManagedObject* _Nullable item))fillingBlock; 27 | 28 | + (NSUInteger)totalCount; 29 | 30 | /** 31 | Just fetching record items by the predicate in main context. 32 | */ 33 | + (NSArray *)items; 34 | 35 | + (NSArray * _Nullable)itemsOffset:(NSUInteger)offset withLimit:(NSUInteger)limitNumber; 36 | 37 | /** 38 | Fetch record items in main context by predicate. 39 | */ 40 | + (NSArray *)itemsWithPredicate:(NSPredicate *)predicate; 41 | 42 | /** 43 | Fetch record items in main context by formated string. 44 | */ 45 | + (NSArray *)itemsWithFormat:(NSString *)fmt,...; 46 | 47 | /** 48 | * Fetch record items in main context by predicate format string more simpler. 49 | * 50 | * @param sortDescriptions SortDescriptions 51 | * @param fmt Predicate format string. 52 | * 53 | * @return Array of items match the condition. 54 | */ 55 | + (NSArray *)itemsSortDescriptions:(NSArray *)sortDescriptions withFormat:(NSString *)fmt,...; 56 | 57 | /** 58 | * Fetch record items in main context by predicate format string more simpler. 59 | * 60 | * @param sortDescriptions SortDescriptions 61 | * @param offset offset 62 | * @param limitNumber limit number 63 | * @param fmt predicate format string. 64 | * 65 | * @return Array of items match the condition. 66 | */ 67 | + (NSArray *)itemsSortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber withFormat:(NSString *)fmt,...; 68 | 69 | + (NSArray *)itemsWithSortDescriptions:(NSArray * _Nullable)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber andPredicate:(NSPredicate* _Nullable)predicate; 70 | 71 | /** 72 | * Fetching last record item. 73 | */ 74 | + (instancetype)lastItem; 75 | 76 | /** 77 | * Fetch record item by predicate in main context. 78 | * 79 | * @param predicate Predicate object.s 80 | * 81 | * @return Last item of the managed object in context. 82 | */ 83 | + (instancetype)lastItemWithPredicate:(NSPredicate *)predicate; 84 | 85 | /** 86 | 87 | */ 88 | /** 89 | * Fetch record item by formated string in main context. 90 | * 91 | * @param fmt Predicate format. 92 | * 93 | * @return Last item of the managed object in context. 94 | */ 95 | + (instancetype)lastItemWithFormat:(NSString *)fmt,...; 96 | 97 | @end 98 | 99 | NS_ASSUME_NONNULL_END 100 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/ManagedObject/NSManagedObject_MainThread.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSManagedObject_MainThread.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "NSManagedObject_MainThread.h" 10 | 11 | #import "CoreDataEnvir_Main.h" 12 | #import "CoreDataEnvir_Private.h" 13 | #import "CoreDataEnvir.h" 14 | #import "NSManagedObject_Convenient.h" 15 | 16 | @implementation NSManagedObject (CDEMainThread) 17 | 18 | 19 | /** 20 | * Insert an item. 21 | * 22 | * @return NSManagedObject 23 | */ 24 | + (instancetype)insertItem 25 | { 26 | if (![NSThread isMainThread]) { 27 | #if DEBUG 28 | NSLog(@"Insert item record failed, please run on main thread!"); 29 | #endif 30 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Insert item record failed, must run on main thread!" userInfo:nil] raise]; 31 | return nil; 32 | } 33 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 34 | id item = [self insertItemInContext:db]; 35 | return item; 36 | } 37 | 38 | /** 39 | * Insert an item by block 40 | * 41 | * @param fillingBlock Fill data 42 | * 43 | * @return NSManagedObject 44 | */ 45 | + (instancetype)insertItemWithFillingBlock:(void (^)(id _Nullable item))fillingBlock 46 | { 47 | id item = [self insertItem]; 48 | fillingBlock(item); 49 | return item; 50 | } 51 | 52 | + (NSUInteger)totalCount { 53 | if (![NSThread isMainThread]) { 54 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch all items record failed, must run on main thread!" userInfo:nil] raise]; 55 | return NSUIntegerMax; 56 | } 57 | 58 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 59 | NSFetchRequest* req = [self newFetchRequestInContext:db]; 60 | return [db countForFetchRequest:req error:nil]; 61 | } 62 | 63 | + (NSArray *)items 64 | { 65 | if (![NSThread isMainThread]) { 66 | #if DEBUG 67 | NSLog(@"Fetch all items record failed, please run on main thread!"); 68 | #endif 69 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch all items record failed, must run on main thread!" userInfo:nil] raise]; 70 | return nil; 71 | } 72 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 73 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self)]; 74 | 75 | return items; 76 | } 77 | 78 | + (NSArray *)itemsOffset:(NSUInteger)offset withLimit:(NSUInteger)limitNumber { 79 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 80 | 81 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:nil usingSortDescriptions:nil fromOffset:offset LimitedBy:limitNumber]; 82 | 83 | return items; 84 | } 85 | 86 | + (NSArray *)itemsWithPredicate:(NSPredicate *)predicate 87 | { 88 | if (![NSThread isMainThread]) { 89 | #if DEBUG 90 | NSLog(@"Fetch item record failed, please run on main thread!"); 91 | #endif 92 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch item record failed, must run on main thread!" userInfo:nil] raise]; 93 | return nil; 94 | } 95 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 96 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:predicate]; 97 | return items; 98 | } 99 | 100 | + (NSArray *)itemsWithFormat:(NSString *)fmt, ... 101 | { 102 | if (![NSThread isMainThread]) { 103 | #if DEBUG 104 | NSLog(@"Fetch item record failed, please run on main thread!"); 105 | #endif 106 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch item record failed, must run on main thread!" userInfo:nil] raise]; 107 | return nil; 108 | } 109 | 110 | va_list args; 111 | va_start(args, fmt); 112 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 113 | va_end(args); 114 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 115 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred]; 116 | return items; 117 | } 118 | 119 | + (NSArray *)itemsSortDescriptions:(NSArray *)sortDescriptions withFormat:(NSString *)fmt, ... 120 | { 121 | if (![NSThread isMainThread]) { 122 | #if DEBUG 123 | NSLog(@"Fetch item record failed, please run on main thread!"); 124 | #endif 125 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch item record failed, must run on main thread!" userInfo:nil] raise]; 126 | return nil; 127 | } 128 | 129 | va_list args; 130 | va_start(args, fmt); 131 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 132 | va_end(args); 133 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 134 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred usingSortDescriptions:sortDescriptions]; 135 | return items; 136 | } 137 | 138 | + (NSArray *)itemsSortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber withFormat:(NSString *)fmt, ... 139 | { 140 | if (![NSThread isMainThread]) { 141 | #if DEBUG 142 | NSLog(@"Fetch item record failed, please run on main thread!"); 143 | #endif 144 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch item record failed, must run on main thread!" userInfo:nil] raise]; 145 | return nil; 146 | } 147 | 148 | va_list args; 149 | va_start(args, fmt); 150 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 151 | va_end(args); 152 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 153 | NSArray *items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:pred usingSortDescriptions:sortDescriptions fromOffset:offset LimitedBy:limitNumber]; 154 | return items; 155 | } 156 | 157 | + (NSArray *)itemsWithSortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)offset limitedBy:(NSUInteger)limitNumber andPredicate:(NSPredicate *)predicate { 158 | CoreDataEnvir *db = [CoreDataEnvir mainInstance]; 159 | NSArray* items = [db fetchItemsByEntityDescriptionName:NSStringFromClass(self) usingPredicate:predicate usingSortDescriptions:sortDescriptions fromOffset:offset LimitedBy:limitNumber]; 160 | return items; 161 | } 162 | 163 | + (instancetype)lastItem 164 | { 165 | if (![NSThread isMainThread]) { 166 | #if DEBUG 167 | NSLog(@"Fetch last item record failed, please run on main thread!"); 168 | #endif 169 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch last item record failed, must run on main thread!" userInfo:nil] raise]; 170 | return nil; 171 | } 172 | 173 | return [[self items] lastObject]; 174 | } 175 | 176 | + (instancetype)lastItemWithPredicate:(NSPredicate *)predicate 177 | { 178 | if (![NSThread isMainThread]) { 179 | #if DEBUG 180 | NSLog(@"Fetch last item record failed, please run on main thread!"); 181 | #endif 182 | [[NSException exceptionWithName:@"CoreDataEnviroment" reason:@"Fetch last item record failed, must run on main thread!" userInfo:nil] raise]; 183 | return nil; 184 | } 185 | 186 | return [[self itemsInContext:[CoreDataEnvir mainInstance] usingPredicate:predicate] lastObject]; 187 | } 188 | 189 | + (instancetype)lastItemWithFormat:(NSString *)fmt, ... 190 | { 191 | va_list args; 192 | va_start(args, fmt); 193 | NSPredicate *pred = [NSPredicate predicateWithFormat:fmt arguments:args]; 194 | va_end(args); 195 | return [self lastItemWithPredicate:pred]; 196 | } 197 | 198 | @end 199 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/Private/CoreDataEnvir_Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir_Private.h 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | extern id _Nullable _rescureDelegate; 15 | extern CoreDataEnvir* _Nullable _backgroundInstance; 16 | extern CoreDataEnvir* _Nullable _mainInstance; 17 | extern long _create_counter; 18 | 19 | @interface CoreDataEnvir (CDEPrivate) 20 | 21 | /** 22 | Rename database file with new registed name. 23 | */ 24 | + (void)_renameDatabaseFile; 25 | 26 | - (NSDictionary*)defaultPersistentOptions; 27 | 28 | - (NSFetchRequest * _Nullable)newFetchRequestWithName:(NSString* _Nullable)name error:(NSError* _Nullable * _Nullable)error; 29 | 30 | - (NSFetchRequest * _Nullable)newFetchRequestWithClass:(Class _Nullable)clazz error:(NSError * _Nullable * _Nullable)error; 31 | 32 | /** 33 | Insert a new record into the table by className. 34 | */ 35 | - (NSManagedObject * _Nullable)buildManagedObjectByName:(NSString * _Nonnull)className error:(NSError**)error; 36 | 37 | /// Insert a new record into the table by Class type. 38 | /// @param theClass Object class 39 | /// @param error NSError with failed information. 40 | - (NSManagedObject* _Nullable)buildManagedObjectByClass:(Class _Nonnull)theClass error:(NSError* _Nullable * _Nullable)error; 41 | 42 | /// Create entity from a 'Class' object 43 | /// @param clazz Class object 44 | - (NSEntityDescription * _Nullable) entityDescriptionByClass:(Class _Nullable)clazz; 45 | 46 | /** 47 | Get entity descritpion from name string 48 | */ 49 | - (NSEntityDescription * _Nullable) entityDescriptionByName:(NSString *_Nullable)className; 50 | 51 | - (NSUInteger)countForFetchRequest:(NSFetchRequest* _Nonnull)fetchRequest error:(NSError* _Nullable * _Nullable)error; 52 | 53 | /** 54 | Fetching record item. 55 | */ 56 | - (NSArray *)fetchItemsByEntityDescriptionName:(NSString *)entityName; 57 | - (NSArray *)fetchItemsByEntityDescriptionName:(NSString *)entityName usingPredicate:(NSPredicate *) predicate; 58 | - (NSArray *)fetchItemsByEntityDescriptionName:(NSString *)entityName usingPredicate:(NSPredicate *)predicate usingSortDescriptions:(NSArray *)sortDescriptions; 59 | - (NSArray *)fetchItemsByEntityDescriptionName:(NSString *)entityName usingPredicate:(NSPredicate * _Nullable) predicate usingSortDescriptions:(NSArray * _Nullable)sortDescriptions fromOffset:(NSUInteger) aOffset LimitedBy:(NSUInteger)aLimited; 60 | 61 | /** 62 | * Update context while data changes. 63 | * 64 | * @param notification NSNotification object. 65 | */ 66 | - (void)updateContext:(NSNotification *)notification; 67 | 68 | /** 69 | * Merge context data while other context occur data changing. 70 | * 71 | * @param notification NSNotification object. 72 | */ 73 | - (void)mergeChanges:(NSNotification *)notification; 74 | 75 | /** 76 | Send processPendingChanges message on non-main thread. 77 | You should call this method after cluster of actions. 78 | */ 79 | - (void)sendPendingChanges; 80 | 81 | 82 | 83 | @end 84 | 85 | NS_ASSUME_NONNULL_END 86 | -------------------------------------------------------------------------------- /src/CoreDataEnvir/Private/CoreDataEnvir_Private.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreDataEnvir_Private.m 3 | // CoreDataEnvirSample 4 | // 5 | // Created by NicholasXu on 15/8/30. 6 | // Copyright (c) 2015年 Nicholas.Xu. All rights reserved. 7 | // 8 | 9 | #import "CoreDataEnvir_Private.h" 10 | 11 | #import "CoreDataEnvir_Main.h" 12 | 13 | id _rescureDelegate; 14 | CoreDataEnvir *_backgroundInstance = nil; 15 | CoreDataEnvir *_mainInstance = nil; 16 | long _create_counter = 0; 17 | 18 | @implementation CoreDataEnvir (CDEPrivate) 19 | 20 | - (NSDictionary *)defaultPersistentOptions { 21 | NSDictionary *options = @{ 22 | NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES 23 | }; 24 | return options; 25 | } 26 | 27 | - (NSFetchRequest *)newFetchRequestWithName:(NSString *)name error:(NSError **)error { 28 | NSEntityDescription *entity = [NSEntityDescription entityForName:name inManagedObjectContext:self.context]; 29 | if (!entity) { 30 | *error = [NSError errorWithDomain:@"CoreDataEnvir: entity create failed" code:0 userInfo:nil]; 31 | return nil; 32 | } 33 | NSFetchRequest *req = [[NSFetchRequest alloc] init]; 34 | [req setEntity:entity]; 35 | return req; 36 | } 37 | 38 | - (NSFetchRequest *)newFetchRequestWithClass:(Class)clazz error:(NSError **)error { 39 | if (!clazz) { 40 | *error = [NSError errorWithDomain:@"CoreDataEnvir: class is nil." code:0 userInfo:nil]; 41 | return nil; 42 | } 43 | NSString* name = NSStringFromClass(clazz); 44 | NSFetchRequest *req = [self newFetchRequestWithName:name error:error]; 45 | return req; 46 | } 47 | 48 | - (NSManagedObject *) buildManagedObjectByName:(NSString *)className error:(NSError *__autoreleasing _Nullable * _Nullable)error 49 | { 50 | NSManagedObject *_object = nil; 51 | _object = [NSEntityDescription insertNewObjectForEntityForName:className inManagedObjectContext:self.context]; 52 | if (!_object) { 53 | NSString* msg = [NSString stringWithFormat:@"Error(%@): Insert object of class:(%@) failed", CDE_DOMAIN, className]; 54 | if (*error) { 55 | *error = [NSError errorWithDomain:msg code:0 userInfo:nil]; 56 | } 57 | NSAssert(false, msg); 58 | return nil; 59 | } 60 | 61 | return _object; 62 | } 63 | 64 | - (NSManagedObject *)buildManagedObjectByClass:(Class)theClass error:(NSError **)error { 65 | NSManagedObject *_object = nil; 66 | NSString* className = NSStringFromClass(theClass); 67 | if (!className) { 68 | NSString* msg = [NSString stringWithFormat:@"Error(%@): class: \"%@\" name not found.", CDE_DOMAIN, className]; 69 | if (*error) { 70 | *error = [NSError errorWithDomain:msg code:0 userInfo:0]; 71 | } 72 | NSAssert(false, msg); 73 | return nil; 74 | } 75 | 76 | _object = [self buildManagedObjectByName:className error:error]; 77 | return _object; 78 | } 79 | 80 | - (NSEntityDescription *)entityDescriptionByClass:(Class)clazz { 81 | NSString* name = NSStringFromClass(clazz); 82 | return [self entityDescriptionByName:name]; 83 | } 84 | 85 | - (NSEntityDescription *) entityDescriptionByName:(NSString *)className 86 | { 87 | return [NSEntityDescription entityForName:className inManagedObjectContext:self.context]; 88 | } 89 | 90 | - (NSUInteger)countForFetchRequest:(NSFetchRequest *)fetchRequest error:(NSError **)error { 91 | return [self.context countForFetchRequest:fetchRequest error:error]; 92 | } 93 | 94 | - (NSArray *) fetchItemsByEntityDescriptionName:(NSString *)entityName 95 | { 96 | NSArray *items = nil; 97 | 98 | NSEntityDescription* entity = [self entityDescriptionByName:entityName]; 99 | if (!entity) { 100 | return nil; 101 | } 102 | 103 | NSFetchRequest *req = [[NSFetchRequest alloc] init]; 104 | [req setEntity:entity]; 105 | 106 | NSError *error = nil; 107 | items = [self.context executeFetchRequest:req error:&error]; 108 | if (error) { 109 | NSLog(@"%s, error:%@, entityName:%@", __FUNCTION__, error, entityName); 110 | } 111 | 112 | return items; 113 | } 114 | 115 | - (NSArray *) fetchItemsByEntityDescriptionName:(NSString *)entityName usingPredicate:(NSPredicate *)predicate 116 | { 117 | NSArray *items = nil; 118 | 119 | NSFetchRequest *req = [[NSFetchRequest alloc] init]; 120 | [req setEntity:[self entityDescriptionByName:entityName]]; 121 | [req setPredicate:predicate]; 122 | 123 | NSError *error = nil; 124 | items = [self.context executeFetchRequest:req error:&error]; 125 | if (error) { 126 | NSLog(@"%s, error:%@, entityName:%@", __FUNCTION__, [error localizedDescription], entityName); 127 | } 128 | 129 | return items; 130 | } 131 | 132 | - (NSArray *) fetchItemsByEntityDescriptionName:(NSString *)entityName usingPredicate:(NSPredicate *)predicate usingSortDescriptions:(NSArray *)sortDescriptions 133 | { 134 | NSArray *items = nil; 135 | 136 | NSFetchRequest *req = [[NSFetchRequest alloc] init]; 137 | NSEntityDescription * entityDescritpion = [self entityDescriptionByName:entityName]; 138 | [req setEntity:entityDescritpion]; 139 | [req setSortDescriptors:sortDescriptions]; 140 | [req setPredicate:predicate]; 141 | NSError *error = nil; 142 | items = [self.context executeFetchRequest:req error:&error]; 143 | if (error) { 144 | NSLog(@"%s, error:%@", __FUNCTION__, [error localizedDescription]); 145 | } 146 | 147 | return items; 148 | } 149 | 150 | - (NSArray *) fetchItemsByEntityDescriptionName:(NSString *)entityName usingPredicate:(NSPredicate *)predicate usingSortDescriptions:(NSArray *)sortDescriptions fromOffset:(NSUInteger)aOffset LimitedBy:(NSUInteger)aLimited 151 | { 152 | NSArray *items = nil; 153 | 154 | NSFetchRequest *req = [[NSFetchRequest alloc] init]; 155 | NSEntityDescription * entityDescritpion = [self entityDescriptionByName:entityName]; 156 | [req setEntity:entityDescritpion]; 157 | [req setSortDescriptors:sortDescriptions]; 158 | [req setPredicate:predicate]; 159 | [req setFetchOffset:aOffset]; 160 | [req setFetchLimit:aLimited]; 161 | 162 | NSError *error = nil; 163 | 164 | items = [self.context executeFetchRequest:req error:&error]; 165 | 166 | if (error) { 167 | NSLog(@"%s, error:%@", __FUNCTION__, [error localizedDescription]); 168 | } 169 | 170 | return items; 171 | } 172 | 173 | - (void)updateContext:(NSNotification *)notification 174 | { 175 | #if DEBUG && CORE_DATA_ENVIR_SHOW_LOG 176 | NSLog(@"%s %@ ->>> %@", __FUNCTION__, notification.object, self.context); 177 | #endif 178 | 179 | void (^doWork)(void) = ^ { 180 | @try { 181 | //After this merge operating, context update it's state 'hasChanges' . 182 | [self.context mergeChangesFromContextDidSaveNotification:notification]; 183 | } 184 | @catch (NSException *exception) { 185 | NSLog(@"exce :%@", exception); 186 | } 187 | @finally { 188 | //NSLog(@"Merge finished!"); 189 | } 190 | }; 191 | #pragma clang push 192 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 193 | if ([[UIDevice currentDevice] systemVersion].floatValue >= 8.0) { 194 | [self.persistentStoreCoordinator performBlockAndWait:doWork]; 195 | }else { 196 | [self.persistentStoreCoordinator lock]; 197 | doWork(); 198 | [self.persistentStoreCoordinator unlock]; 199 | } 200 | #pragma clang pop 201 | 202 | } 203 | 204 | /** 205 | 206 | this is called via observing "NSManagedObjectContextDidSaveNotification" from our ParseOperation 207 | 208 | */ 209 | - (void)mergeChanges:(NSNotification *)notification { 210 | #if DEBUG && CORE_DATA_ENVIR_SHOW_LOG 211 | NSLog(@"%s [%@/%@] %@", __FUNCTION__, self.context, notification.object, [self currentDispatchQueueLabel]); 212 | #endif 213 | 214 | if (notification.object == self.context) { 215 | // main context save, no need to perform the merge 216 | return; 217 | } 218 | 219 | //[self performSelectorOnMainThread:@selector(updateContext:) withObject:notification waitUntilDone:NO]; 220 | //Note:waitUntilDone:YES will cause method 'saveDatabase' and 'updateContext' fall in dead lock by '[storeCoordinator lock]' 221 | [self performSelector:@selector(updateContext:) onThread:[NSThread currentThread] withObject:notification waitUntilDone:YES]; 222 | } 223 | 224 | - (void)sendPendingChanges 225 | { 226 | if ([NSThread isMainThread] || 227 | !self.context) { 228 | return; 229 | } 230 | [self.context processPendingChanges]; 231 | } 232 | 233 | 234 | @end 235 | -------------------------------------------------------------------------------- /syncgit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | git push origin --all 4 | --------------------------------------------------------------------------------