├── CoreDataExample.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── bryan.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── bryan.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── CoreDataExample.xcscheme
│ └── xcschememanagement.plist
├── CoreDataExample.xcworkspace
├── contents.xcworkspacedata
├── xcshareddata
│ └── CoreDataExample.xccheckout
└── xcuserdata
│ └── bryan.xcuserdatad
│ ├── UserInterfaceState.xcuserstate
│ ├── WorkspaceSettings.xcsettings
│ └── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
├── CoreDataExample
├── CoreDataExample-Info.plist
├── CoreDataExample-Prefix.pch
├── CoreDataExample.xcdatamodeld
│ ├── .xccurrentversion
│ └── CoreDataExample.xcdatamodel
│ │ └── contents
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── TMAppDelegate.h
├── TMAppDelegate.m
├── TMCoreDataController.h
├── TMCoreDataController.m
├── TMDashboardViewController.h
├── TMDashboardViewController.m
├── TMFetchedResultsControllerDelegate.h
├── TMFetchedResultsControllerDelegate.m
├── TMPost.h
├── TMPost.m
├── en.lproj
│ └── InfoPlist.strings
└── main.m
├── LICENSE
├── Podfile
├── Podfile.lock
├── Pods
├── BuildHeaders
│ ├── JXHTTP
│ │ ├── JXHTTP.h
│ │ ├── JXHTTPDataBody.h
│ │ ├── JXHTTPFileBody.h
│ │ ├── JXHTTPFormEncodedBody.h
│ │ ├── JXHTTPJSONBody.h
│ │ ├── JXHTTPMultipartBody.h
│ │ ├── JXHTTPOperation+Convenience.h
│ │ ├── JXHTTPOperation.h
│ │ ├── JXHTTPOperationDelegate.h
│ │ ├── JXHTTPOperationQueue.h
│ │ ├── JXHTTPOperationQueueDelegate.h
│ │ ├── JXHTTPRequestBody.h
│ │ ├── JXOperation.h
│ │ ├── JXURLConnectionOperation.h
│ │ └── JXURLEncoding.h
│ └── TMTumblrSDK
│ │ ├── TMAPIClient.h
│ │ ├── TMOAuth.h
│ │ ├── TMSDKFunctions.h
│ │ ├── TMTumblrActivity.h
│ │ ├── TMTumblrAppClient.h
│ │ └── TMTumblrAuthenticator.h
├── Headers
│ ├── JXHTTP
│ │ ├── JXHTTP.h
│ │ ├── JXHTTPDataBody.h
│ │ ├── JXHTTPFileBody.h
│ │ ├── JXHTTPFormEncodedBody.h
│ │ ├── JXHTTPJSONBody.h
│ │ ├── JXHTTPMultipartBody.h
│ │ ├── JXHTTPOperation+Convenience.h
│ │ ├── JXHTTPOperation.h
│ │ ├── JXHTTPOperationDelegate.h
│ │ ├── JXHTTPOperationQueue.h
│ │ ├── JXHTTPOperationQueueDelegate.h
│ │ ├── JXHTTPRequestBody.h
│ │ ├── JXOperation.h
│ │ ├── JXURLConnectionOperation.h
│ │ └── JXURLEncoding.h
│ └── TMTumblrSDK
│ │ ├── TMAPIClient.h
│ │ ├── TMOAuth.h
│ │ ├── TMSDKFunctions.h
│ │ ├── TMTumblrActivity.h
│ │ ├── TMTumblrAppClient.h
│ │ └── TMTumblrAuthenticator.h
├── JXHTTP
│ ├── JXHTTP
│ │ ├── JXHTTP.h
│ │ ├── JXHTTPDataBody.h
│ │ ├── JXHTTPDataBody.m
│ │ ├── JXHTTPFileBody.h
│ │ ├── JXHTTPFileBody.m
│ │ ├── JXHTTPFormEncodedBody.h
│ │ ├── JXHTTPFormEncodedBody.m
│ │ ├── JXHTTPJSONBody.h
│ │ ├── JXHTTPJSONBody.m
│ │ ├── JXHTTPMultipartBody.h
│ │ ├── JXHTTPMultipartBody.m
│ │ ├── JXHTTPOperation+Convenience.h
│ │ ├── JXHTTPOperation+Convenience.m
│ │ ├── JXHTTPOperation.h
│ │ ├── JXHTTPOperation.m
│ │ ├── JXHTTPOperationDelegate.h
│ │ ├── JXHTTPOperationQueue.h
│ │ ├── JXHTTPOperationQueue.m
│ │ ├── JXHTTPOperationQueueDelegate.h
│ │ ├── JXHTTPRequestBody.h
│ │ ├── JXOperation.h
│ │ ├── JXOperation.m
│ │ ├── JXURLConnectionOperation.h
│ │ ├── JXURLConnectionOperation.m
│ │ ├── JXURLEncoding.h
│ │ └── JXURLEncoding.m
│ ├── LICENSE.txt
│ └── README.md
├── Manifest.lock
├── Pods-JXHTTP-Private.xcconfig
├── Pods-JXHTTP-dummy.m
├── Pods-JXHTTP-prefix.pch
├── Pods-JXHTTP.xcconfig
├── Pods-TMTumblrSDK-Private.xcconfig
├── Pods-TMTumblrSDK-dummy.m
├── Pods-TMTumblrSDK-prefix.pch
├── Pods-TMTumblrSDK.xcconfig
├── Pods-acknowledgements.markdown
├── Pods-acknowledgements.plist
├── Pods-dummy.m
├── Pods-environment.h
├── Pods-resources.sh
├── Pods.xcconfig
├── Pods.xcodeproj
│ ├── project.pbxproj
│ └── xcuserdata
│ │ └── bryan.xcuserdatad
│ │ └── xcschemes
│ │ ├── Pods-JXHTTP.xcscheme
│ │ ├── Pods-TMTumblrSDK.xcscheme
│ │ ├── Pods.xcscheme
│ │ └── xcschememanagement.plist
└── TMTumblrSDK
│ ├── LICENSE
│ ├── README.md
│ └── TMTumblrSDK
│ ├── APIClient
│ ├── TMAPIClient.h
│ └── TMAPIClient.m
│ ├── Activity
│ ├── TMTumblrActivity.h
│ ├── TMTumblrActivity.m
│ ├── UIActivityTumblr.png
│ ├── UIActivityTumblr@2x.png
│ ├── UIActivityTumblr@2x~ipad.png
│ ├── UIActivityTumblr~ipad.png
│ └── UIActivityTumblr~ipad@2x.png
│ ├── AppClient
│ ├── TMTumblrAppClient.h
│ └── TMTumblrAppClient.m
│ ├── Authentication
│ ├── TMOAuth.h
│ ├── TMOAuth.m
│ ├── TMTumblrAuthenticator.h
│ └── TMTumblrAuthenticator.m
│ └── Core
│ ├── TMSDKFunctions.h
│ └── TMSDKFunctions.m
└── README.md
/CoreDataExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CoreDataExample.xcodeproj/project.xcworkspace/xcuserdata/bryan.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TumblrArchive/CoreDataExample/fdcba11b8581ccafeceaa7423967f332c985ffb5/CoreDataExample.xcodeproj/project.xcworkspace/xcuserdata/bryan.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/CoreDataExample.xcodeproj/xcuserdata/bryan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/CoreDataExample.xcodeproj/xcuserdata/bryan.xcuserdatad/xcschemes/CoreDataExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
61 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/CoreDataExample.xcodeproj/xcuserdata/bryan.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | CoreDataExample.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 939BCF57193CBB9B00B84FB1
16 |
17 | primary
18 |
19 |
20 | 939BCF77193CBB9B00B84FB1
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/CoreDataExample.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/CoreDataExample.xcworkspace/xcshareddata/CoreDataExample.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 6785B030-705A-4105-A855-195C308374DE
9 | IDESourceControlProjectName
10 | CoreDataExample
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | FB730834-BBA2-4C16-B6E0-7021D7A17E58
14 | ssh://github.ewr01.tumblr.net/bryan/CoreDataExample.git
15 |
16 | IDESourceControlProjectPath
17 | CoreDataExample.xcworkspace
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | FB730834-BBA2-4C16-B6E0-7021D7A17E58
21 | ..
22 |
23 | IDESourceControlProjectURL
24 | ssh://github.ewr01.tumblr.net/bryan/CoreDataExample.git
25 | IDESourceControlProjectVersion
26 | 110
27 | IDESourceControlProjectWCCIdentifier
28 | FB730834-BBA2-4C16-B6E0-7021D7A17E58
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | FB730834-BBA2-4C16-B6E0-7021D7A17E58
36 | IDESourceControlWCCName
37 | CoreDataExample
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/CoreDataExample.xcworkspace/xcuserdata/bryan.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TumblrArchive/CoreDataExample/fdcba11b8581ccafeceaa7423967f332c985ffb5/CoreDataExample.xcworkspace/xcuserdata/bryan.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/CoreDataExample.xcworkspace/xcuserdata/bryan.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges
6 |
7 | SnapshotAutomaticallyBeforeSignificantChanges
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/CoreDataExample.xcworkspace/xcuserdata/bryan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/CoreDataExample/CoreDataExample-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | me.irace.${PRODUCT_NAME:rfc1034identifier}
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 |
38 |
39 |
--------------------------------------------------------------------------------
/CoreDataExample/CoreDataExample-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_3_0
10 | #warning "This project uses features only available in iOS SDK 3.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #import
17 | #endif
18 |
--------------------------------------------------------------------------------
/CoreDataExample/CoreDataExample.xcdatamodeld/.xccurrentversion:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | _XCCurrentVersionName
6 | CoreDataExample.xcdatamodel
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CoreDataExample/CoreDataExample.xcdatamodeld/CoreDataExample.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/CoreDataExample/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/CoreDataExample/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/CoreDataExample/TMAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMAppDelegate.h
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TMAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/CoreDataExample/TMAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMAppDelegate.m
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMAppDelegate.h"
10 | #import "TMDashboardViewController.h"
11 | #import "TMAPIClient.h"
12 | #import "TMCoreDataController.h"
13 |
14 | @implementation TMAppDelegate
15 |
16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
17 | [[TMCoreDataController sharedInstance] setUp];
18 |
19 | #warning Needs keys/secrets
20 | /*
21 | In order for this to work, you need to create a Tumblr API application, which can be done here: https://www.tumblr.com/oauth/apps.
22 | You can then use the API console to get a token and token secret: https://api.tumblr.com/console
23 | */
24 | [TMAPIClient sharedInstance].OAuthConsumerKey = @"";
25 | [TMAPIClient sharedInstance].OAuthConsumerSecret = @"";
26 | [TMAPIClient sharedInstance].OAuthToken = @"";
27 | [TMAPIClient sharedInstance].OAuthTokenSecret = @"";
28 |
29 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
30 | self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[TMDashboardViewController alloc] init]];
31 | self.window.backgroundColor = [UIColor whiteColor];
32 | [self.window makeKeyAndVisible];
33 |
34 | return YES;
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/CoreDataExample/TMCoreDataController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMCoreDataController.h
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | typedef void (^TMCoreDataControllerBlock)(NSManagedObjectContext *context);
10 |
11 | /**
12 | * Encapsulates an entire [Core Data stack](http://floriankugler.com/blog/2013/4/2/the-concurrent-core-data-stack)
13 | * and exposes methods necessary to perform operations on managed object contexts associated with both the main queue
14 | * and a private queue.
15 | */
16 | @interface TMCoreDataController : NSObject
17 |
18 | /**
19 | * Context associated with the main queue. Can be passed directly to read-only methods that require a context but don't
20 | * require the context to be saved afterwards (in which case `performMainContextBlock:` would be a better option).
21 | */
22 | @property (nonatomic, strong, readonly) NSManagedObjectContext *mainContext;
23 |
24 | + (instancetype)sharedInstance;
25 |
26 | - (void)setUp;
27 |
28 | /**
29 | * Provides a block with a private queue context and performs the block on the aforementioned queue, synchronously.
30 | * Saves the context (and any ancestor contexts, recursively) afterwards.
31 | *
32 | * @param block Block provided with a private queue context and performed on the aforementioned queue.
33 | */
34 | - (void)performBackgroundBlockAndWait:(TMCoreDataControllerBlock)block;
35 |
36 | /**
37 | * Provides a block with the main queue context and performs the block on the main queue, synchronously.
38 | * Saves the context (and any ancestor contexts, recursively) afterwards.
39 | *
40 | * @param block Block provided with the main queue context and performed on the main queue.
41 | */
42 | - (void)performMainContextBlock:(TMCoreDataControllerBlock)block;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/CoreDataExample/TMCoreDataController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMCoreDataController.m
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMCoreDataController.h"
10 |
11 | static NSString * const ManagedObjectModelResourceName = @"CoreDataExample";
12 | static NSString * const ManagedObjectModelExtension = @"momd";
13 | static NSString * const PersistentStorePath = @"Tumblr.sqlite";
14 |
15 | @interface TMCoreDataController()
16 |
17 | @property (nonatomic, strong) NSManagedObjectContext *masterContext;
18 | @property (nonatomic, strong) NSManagedObjectContext *mainContext;
19 |
20 | @end
21 |
22 | @implementation TMCoreDataController
23 |
24 | #pragma mark - Initialization
25 |
26 | + (instancetype)sharedInstance {
27 | static TMCoreDataController *instance;
28 |
29 | static dispatch_once_t onceToken;
30 | dispatch_once(&onceToken, ^{
31 | instance = [[self alloc] init];
32 | });
33 |
34 | return instance;
35 | }
36 |
37 | - (void)setUp {
38 | NSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:
39 | [[NSBundle mainBundle] URLForResource:ManagedObjectModelResourceName
40 | withExtension:ManagedObjectModelExtension]];
41 |
42 | NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel];
43 |
44 | _masterContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
45 | _masterContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
46 | _masterContext.persistentStoreCoordinator = persistentStoreCoordinator;
47 |
48 | _mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
49 | _mainContext.parentContext = _masterContext;
50 |
51 | NSURL *persistentStoreURL = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
52 | firstObject]
53 | URLByAppendingPathComponent:PersistentStorePath];
54 |
55 | [self addPersistentStoreAtURL:persistentStoreURL toCoordinator:persistentStoreCoordinator requiringCompatabilityWithModel:managedObjectModel];
56 |
57 | void (^registerToSaveMainContextWhenObservingNotificationWithName)(NSString *) = ^(NSString *notificationName) {
58 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveMainContext) name:notificationName object:nil];
59 | };
60 | registerToSaveMainContextWhenObservingNotificationWithName(UIApplicationDidEnterBackgroundNotification);
61 | registerToSaveMainContextWhenObservingNotificationWithName(UIApplicationWillTerminateNotification);
62 | }
63 |
64 | #pragma mark - Private
65 |
66 | /**
67 | * Add a persistent store to a coordinator. If a store already exists on disk, reuse it iff it is compatable with the
68 | * provided managed object model. Otherwise, delete the store on disk and create a new one.
69 | */
70 | - (NSPersistentStore *)addPersistentStoreAtURL:(NSURL *)persistentStoreURL
71 | toCoordinator:(NSPersistentStoreCoordinator *)coordinator
72 | requiringCompatabilityWithModel:(NSManagedObjectModel *)model {
73 | BOOL storeWasRecreated = NO;
74 |
75 | if ([[NSFileManager defaultManager] fileExistsAtPath:[persistentStoreURL path]]) {
76 | NSError *storeMetadataError = nil;
77 | NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
78 | URL:persistentStoreURL
79 | error:&storeMetadataError];
80 |
81 | // If store is incompatible with the managed object model, remove the store file
82 | if (storeMetadataError || ![model isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) {
83 | storeWasRecreated = YES;
84 |
85 | NSError *removeStoreError = nil;
86 |
87 | if (![[NSFileManager defaultManager] removeItemAtURL:persistentStoreURL error:&removeStoreError]) {
88 | NSLog(@"Error removing store file at URL '%@': %@, %@", persistentStoreURL, removeStoreError, [removeStoreError userInfo]);
89 | }
90 | }
91 | }
92 |
93 | NSError *addStoreError = nil;
94 | NSPersistentStore *store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:persistentStoreURL
95 | options:nil error:&addStoreError];
96 |
97 | if (!store) {
98 | NSLog(@"Unable to add store: %@, %@", addStoreError, [addStoreError userInfo]);
99 | }
100 |
101 | return store;
102 | }
103 |
104 | /**
105 | * Save the provided managed object context as well as its parent context(s) (recursively)
106 | */
107 | - (void)saveContext:(NSManagedObjectContext *)context {
108 | if ([context hasChanges]) {
109 | NSError *error;
110 |
111 | if (![context save:&error]) {
112 | NSLog(@"Error saving context: %@ %@ %@", self, error, [error userInfo]);
113 | }
114 |
115 | [self saveContext:context.parentContext];
116 | }
117 | }
118 |
119 | /**
120 | * Save the main queue's context as well as its parent context(s) (recursively)
121 | */
122 | - (void)saveMainContext {
123 | [self saveContext:self.mainContext];
124 | }
125 |
126 | #pragma mark - Block operations
127 |
128 | /**
129 | * Perform a block on a new context (with private queue concurrency type), and then save the context as well as its
130 | * parent context(s) (recursively).
131 | */
132 | - (void)performBackgroundBlockAndWait:(TMCoreDataControllerBlock)block {
133 | NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
134 | backgroundContext.parentContext = self.mainContext;
135 |
136 | if (block) {
137 | [backgroundContext performBlockAndWait:^{
138 | block(backgroundContext);
139 |
140 | [self saveContext:backgroundContext];
141 | }];
142 | }
143 | }
144 |
145 | /**
146 | * Perform a block on the main queue's context, and then save the context as well as its parent context(s) (recursively).
147 | */
148 | - (void)performMainContextBlock:(TMCoreDataControllerBlock)block {
149 | if (block) {
150 | block(self.mainContext);
151 |
152 | [self saveMainContext];
153 | }
154 | }
155 |
156 | @end
157 |
--------------------------------------------------------------------------------
/CoreDataExample/TMDashboardViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMDashboardViewController.h
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | @interface TMDashboardViewController : UITableViewController
10 |
11 | @end
12 |
--------------------------------------------------------------------------------
/CoreDataExample/TMDashboardViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMDashboardViewController.m
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMDashboardViewController.h"
10 | #import "TMFetchedResultsControllerDelegate.h"
11 | #import "TMPost.h"
12 | #import "TMAPIClient.h"
13 | #import "TMCoreDataController.h"
14 |
15 | @interface TMDashboardViewController()
16 |
17 | @property (nonatomic) NSFetchedResultsController *fetchedResultsController;
18 | @property (nonatomic) TMFetchedResultsControllerDelegate *fetchedResultsControllerDelegate;
19 |
20 | @end
21 |
22 | @implementation TMDashboardViewController
23 |
24 | - (id)initWithStyle:(UITableViewStyle)style {
25 | if (self = [super initWithStyle:style]) {
26 | self.title = @"Dashboard";
27 | }
28 |
29 | return self;
30 | }
31 |
32 | #pragma mark - UIViewController
33 |
34 | - (void)viewDidLoad {
35 | [super viewDidLoad];
36 |
37 | self.refreshControl = [[UIRefreshControl alloc] init];
38 | [self.refreshControl addTarget:self action:@selector(refresh) forControlEvents:UIControlEventValueChanged];
39 |
40 | self.fetchedResultsControllerDelegate = [[TMFetchedResultsControllerDelegate alloc] initWithTableView:self.tableView];
41 |
42 | self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:[TMPost allPostsFetchRequest]
43 | managedObjectContext:[TMCoreDataController sharedInstance].mainContext
44 | sectionNameKeyPath:nil
45 | cacheName:nil];
46 | self.fetchedResultsController.delegate = self.fetchedResultsControllerDelegate;
47 |
48 | [self.fetchedResultsController performFetch:nil];
49 |
50 | [self refresh];
51 | }
52 |
53 | #pragma mark - Actions
54 |
55 | - (void)refresh {
56 | [[TMAPIClient sharedInstance] dashboard:nil callback:^(NSDictionary *response, NSError *error) {
57 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
58 | [[TMCoreDataController sharedInstance] performBackgroundBlockAndWait:^(NSManagedObjectContext *context) {
59 | // Delete all existing posts
60 |
61 | NSArray *cachedPosts = [context executeFetchRequest:[TMPost allPostsFetchRequest] error:nil];
62 |
63 | for (TMPost *cachedPost in [cachedPosts reverseObjectEnumerator]) {
64 | [context deleteObject:cachedPost];
65 | }
66 |
67 | // Create new posts out of API response
68 |
69 | NSArray *responsePostDictionaries = response[@"posts"];
70 |
71 | for (NSDictionary *responsePostDictionary in responsePostDictionaries) {
72 | [context insertObject:[TMPost postFromDictionary:responsePostDictionary inContext:context]];
73 | }
74 | }];
75 |
76 | dispatch_async(dispatch_get_main_queue(), ^{
77 | [self.refreshControl endRefreshing];
78 | });
79 | });
80 | }];
81 | }
82 |
83 | #pragma mark - UITableViewDataSource
84 |
85 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
86 | return [[self.fetchedResultsController sections] count];
87 | }
88 |
89 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
90 | return [self.fetchedResultsController.sections[section] numberOfObjects];
91 | }
92 |
93 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
94 | static NSString *CellIdentifier = @"CellIdentifier";
95 |
96 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
97 |
98 | if (!cell) {
99 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
100 | }
101 |
102 | TMPost *post = [self.fetchedResultsController objectAtIndexPath:indexPath];
103 |
104 | cell.textLabel.text = post.blogName;
105 | cell.detailTextLabel.text = post.postID;
106 |
107 | return cell;
108 | }
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/CoreDataExample/TMFetchedResultsControllerDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMFetchedResultsControllerDelegate.h
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | @interface TMFetchedResultsControllerDelegate : NSObject
10 |
11 | - (instancetype)initWithTableView:(UITableView *)tableView;
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/CoreDataExample/TMFetchedResultsControllerDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMFetchedResultsControllerDelegate.m
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMFetchedResultsControllerDelegate.h"
10 |
11 | @interface TMFetchedResultsControllerDelegate()
12 |
13 | @property (nonatomic, weak) UITableView *tableView;
14 |
15 | @end
16 |
17 | @implementation TMFetchedResultsControllerDelegate
18 |
19 | - (instancetype)initWithTableView:(UITableView *)tableView {
20 | if (self = [super init]) {
21 | _tableView = tableView;
22 | }
23 |
24 | return self;
25 | }
26 |
27 | #pragma mark - NSFetchedResultsControllerDelegate
28 |
29 | - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
30 | [self.tableView beginUpdates];
31 | }
32 |
33 | - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
34 | [self.tableView endUpdates];
35 | }
36 |
37 | - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo
38 | atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
39 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:sectionIndex];
40 |
41 | switch (type) {
42 | case NSFetchedResultsChangeInsert: {
43 | [self.tableView insertSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
44 |
45 | break;
46 | }
47 | case NSFetchedResultsChangeDelete:{
48 | [self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
49 |
50 | break;
51 | }
52 | }
53 | }
54 |
55 | - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)object atIndexPath:(NSIndexPath *)indexPath
56 | forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
57 |
58 | void (^deleteIndexPathRows)(void) = ^{
59 | [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
60 | };
61 |
62 | void (^insertNewIndexPathRows)(void) = ^{
63 | [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
64 | };
65 |
66 | switch (type) {
67 | case NSFetchedResultsChangeInsert: {
68 | insertNewIndexPathRows();
69 |
70 | break;
71 | }
72 | case NSFetchedResultsChangeDelete: {
73 | deleteIndexPathRows();
74 |
75 | break;
76 | }
77 | case NSFetchedResultsChangeMove: {
78 | deleteIndexPathRows();
79 | insertNewIndexPathRows();
80 |
81 | break;
82 | }
83 | case NSFetchedResultsChangeUpdate: {
84 | [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
85 |
86 | break;
87 | }
88 | }
89 | }
90 |
91 | @end
92 |
--------------------------------------------------------------------------------
/CoreDataExample/TMPost.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMPost.h
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TMPost : NSManagedObject
12 |
13 | @property (nonatomic, copy) NSString *postID;
14 | @property (nonatomic, copy) NSString *blogName;
15 |
16 | + (instancetype)postFromDictionary:(NSDictionary *)dictionary inContext:(NSManagedObjectContext *)context;
17 |
18 | + (NSFetchRequest *)allPostsFetchRequest;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/CoreDataExample/TMPost.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMPost.m
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMPost.h"
10 |
11 | @implementation TMPost
12 |
13 | @dynamic postID;
14 | @dynamic blogName;
15 |
16 | + (instancetype)postFromDictionary:(NSDictionary *)dictionary inContext:(NSManagedObjectContext *)context {
17 | TMPost *post = [[[self class] alloc] initWithEntity:[NSEntityDescription entityForName:@"Post" inManagedObjectContext:context]
18 | insertIntoManagedObjectContext:context];
19 | post.postID = [dictionary[@"id"] stringValue];
20 | post.blogName = dictionary[@"blog_name"];
21 |
22 | return post;
23 | }
24 |
25 | + (NSFetchRequest *)allPostsFetchRequest {
26 | NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Post"];
27 | fetchRequest.predicate = [NSPredicate predicateWithFormat:@"postID != nil"];
28 | fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"postID" ascending:NO]];
29 |
30 | return fetchRequest;
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/CoreDataExample/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/CoreDataExample/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // CoreDataExample
4 | //
5 | // Created by Bryan Irace on 6/2/14.
6 | // Copyright (c) 2014 Bryan Irace. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "TMAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([TMAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '7.0'
2 |
3 | pod 'TMTumblrSDK'
4 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - JXHTTP (1.0.0)
3 | - TMTumblrSDK (1.0.8):
4 | - TMTumblrSDK/Activity
5 | - TMTumblrSDK/APIClient
6 | - TMTumblrSDK/AppClient
7 | - TMTumblrSDK/Core
8 | - TMTumblrSDK/Activity (1.0.8)
9 | - TMTumblrSDK/APIClient (1.0.8):
10 | - JXHTTP (= 1.0.0)
11 | - TMTumblrSDK/APIClient/Authentication
12 | - TMTumblrSDK/APIClient/Authentication (1.0.8):
13 | - JXHTTP (= 1.0.0)
14 | - TMTumblrSDK/Core
15 | - TMTumblrSDK/AppClient (1.0.8):
16 | - TMTumblrSDK/Core
17 | - TMTumblrSDK/Core (1.0.8)
18 |
19 | DEPENDENCIES:
20 | - TMTumblrSDK
21 |
22 | SPEC CHECKSUMS:
23 | JXHTTP: dd1fe9c6fa21e7b2be9724ef2be16c66aafc44b4
24 | TMTumblrSDK: b9fada23e88b42ade2b492a6db95bfb1dff6304b
25 |
26 | COCOAPODS: 0.33.1
27 |
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTP.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTP.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPDataBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPDataBody.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPFileBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPFileBody.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPFormEncodedBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPFormEncodedBody.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPJSONBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPJSONBody.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPMultipartBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPMultipartBody.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPOperation+Convenience.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperation+Convenience.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPOperation.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperation.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPOperationDelegate.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperationDelegate.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPOperationQueue.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperationQueue.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPOperationQueueDelegate.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperationQueueDelegate.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXHTTPRequestBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPRequestBody.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXOperation.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXOperation.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXURLConnectionOperation.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXURLConnectionOperation.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/JXHTTP/JXURLEncoding.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXURLEncoding.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/TMTumblrSDK/TMAPIClient.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/APIClient/TMAPIClient.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/TMTumblrSDK/TMOAuth.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Authentication/TMOAuth.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/TMTumblrSDK/TMSDKFunctions.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Core/TMSDKFunctions.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/TMTumblrSDK/TMTumblrActivity.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Activity/TMTumblrActivity.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/TMTumblrSDK/TMTumblrAppClient.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/AppClient/TMTumblrAppClient.h
--------------------------------------------------------------------------------
/Pods/BuildHeaders/TMTumblrSDK/TMTumblrAuthenticator.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Authentication/TMTumblrAuthenticator.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTP.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTP.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPDataBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPDataBody.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPFileBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPFileBody.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPFormEncodedBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPFormEncodedBody.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPJSONBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPJSONBody.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPMultipartBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPMultipartBody.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPOperation+Convenience.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperation+Convenience.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPOperation.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperation.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPOperationDelegate.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperationDelegate.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPOperationQueue.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperationQueue.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPOperationQueueDelegate.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPOperationQueueDelegate.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXHTTPRequestBody.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXHTTPRequestBody.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXOperation.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXOperation.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXURLConnectionOperation.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXURLConnectionOperation.h
--------------------------------------------------------------------------------
/Pods/Headers/JXHTTP/JXURLEncoding.h:
--------------------------------------------------------------------------------
1 | ../../JXHTTP/JXHTTP/JXURLEncoding.h
--------------------------------------------------------------------------------
/Pods/Headers/TMTumblrSDK/TMAPIClient.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/APIClient/TMAPIClient.h
--------------------------------------------------------------------------------
/Pods/Headers/TMTumblrSDK/TMOAuth.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Authentication/TMOAuth.h
--------------------------------------------------------------------------------
/Pods/Headers/TMTumblrSDK/TMSDKFunctions.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Core/TMSDKFunctions.h
--------------------------------------------------------------------------------
/Pods/Headers/TMTumblrSDK/TMTumblrActivity.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Activity/TMTumblrActivity.h
--------------------------------------------------------------------------------
/Pods/Headers/TMTumblrSDK/TMTumblrAppClient.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/AppClient/TMTumblrAppClient.h
--------------------------------------------------------------------------------
/Pods/Headers/TMTumblrSDK/TMTumblrAuthenticator.h:
--------------------------------------------------------------------------------
1 | ../../TMTumblrSDK/TMTumblrSDK/Authentication/TMTumblrAuthenticator.h
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTP.h:
--------------------------------------------------------------------------------
1 | #pragma HC SVNT DRACONES
2 |
3 | // Core
4 | #import "JXOperation.h"
5 | #import "JXURLConnectionOperation.h"
6 | #import "JXHTTPOperation.h"
7 | #import "JXHTTPOperationQueue.h"
8 |
9 | // Protocol
10 | #import "JXHTTPRequestBody.h"
11 | #import "JXHTTPOperationDelegate.h"
12 | #import "JXHTTPOperationQueueDelegate.h"
13 |
14 | // Convenience
15 | #import "JXURLEncoding.h"
16 | #import "JXHTTPOperation+Convenience.h"
17 |
18 | // Request Body
19 | #import "JXHTTPDataBody.h"
20 | #import "JXHTTPFileBody.h"
21 | #import "JXHTTPFormEncodedBody.h"
22 | #import "JXHTTPJSONBody.h"
23 | #import "JXHTTPMultipartBody.h"
24 |
25 | // Error Logging
26 | #define JXError(error) if (error) { \
27 | NSLog(@"%@ (%d) ERROR: %@", \
28 | [[NSString stringWithUTF8String:__FILE__] lastPathComponent], \
29 | __LINE__, [error localizedDescription]); }
30 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPDataBody.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPDataBody` conforms to and provides functionality for streaming
3 | request bodies directly from memory, with any content type.
4 | */
5 |
6 | #import "JXHTTPRequestBody.h"
7 |
8 | @interface JXHTTPDataBody : NSObject
9 |
10 | /**
11 | The data to upload.
12 | */
13 | @property (strong, nonatomic) NSData *data;
14 |
15 | /**
16 | The MIME content type of the data to upload.
17 | */
18 | @property (copy, nonatomic) NSString *httpContentType;
19 |
20 | /**
21 | Creates a new `JXHTTPDataBody` with the given data.
22 |
23 | @param data The data to upload.
24 | @returns A request body.
25 | */
26 | + (instancetype)withData:(NSData *)data;
27 |
28 | /**
29 | Creates a new `JXHTTPDataBody` with the given data and MIME content type.
30 |
31 | @param data The data to upload.
32 | @param contentType The MIME content type of the data to upload.
33 | @returns A request body.
34 | */
35 | + (instancetype)withData:(NSData *)data contentType:(NSString *)contentType;
36 |
37 | /**
38 | Creates a new `JXHTTPDataBody` with the given data and MIME content type.
39 |
40 | @param data The data to upload.
41 | @param contentType The MIME content type of the data to upload.
42 | @returns A request body.
43 | */
44 | - (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPDataBody.m:
--------------------------------------------------------------------------------
1 | #import "JXHTTPDataBody.h"
2 |
3 | @implementation JXHTTPDataBody
4 |
5 | #pragma mark - Initialization
6 |
7 | - (instancetype)initWithData:(NSData *)data contentType:(NSString *)contentType
8 | {
9 | if (self = [super init]) {
10 | self.data = data;
11 | self.httpContentType = contentType;
12 | }
13 | return self;
14 | }
15 |
16 | + (instancetype)withData:(NSData *)data contentType:(NSString *)contentType
17 | {
18 | return [[self alloc] initWithData:data contentType:contentType];
19 | }
20 |
21 | + (instancetype)withData:(NSData *)data
22 | {
23 | return [self withData:data contentType:nil];
24 | }
25 |
26 | #pragma mark -
27 |
28 | - (NSInputStream *)httpInputStream
29 | {
30 | return [[NSInputStream alloc] initWithData:self.data];
31 | }
32 |
33 | - (long long)httpContentLength
34 | {
35 | return [self.data length];
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPFileBody.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPFileBody` conforms to and provides functionality for streaming
3 | request bodies directly from disk, with any content type.
4 | */
5 |
6 | #import "JXHTTPRequestBody.h"
7 |
8 | @interface JXHTTPFileBody : NSObject
9 |
10 | /**
11 | The path of the file to upload.
12 | */
13 | @property (copy, nonatomic) NSString *filePath;
14 |
15 | /**
16 | The MIME content type of the file to upload.
17 | */
18 | @property (copy, nonatomic) NSString *httpContentType;
19 |
20 | /**
21 | Creates a new `JXHTTPFileBody` with the given local file path.
22 |
23 | @param filePath The local path of the file.
24 | @returns A request body.
25 | */
26 | + (instancetype)withFilePath:(NSString *)filePath;
27 |
28 | /**
29 | Creates a new `JXHTTPFileBody` with the given local file path.
30 |
31 | @param filePath The local path of the file.
32 | @param contentType The MIME content type of the file.
33 | @returns A request body.
34 | */
35 | + (instancetype)withFilePath:(NSString *)filePath contentType:(NSString *)contentType;
36 |
37 | /**
38 | Creates a new `JXHTTPFileBody` with the given local file path.
39 |
40 | @param filePath The local path of the file.
41 | @param contentType The MIME content type of the file.
42 | @returns A request body.
43 | */
44 | - (instancetype)initWithFilePath:(NSString *)filePath contentType:(NSString *)contentType;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPFileBody.m:
--------------------------------------------------------------------------------
1 | #import "JXHTTPFileBody.h"
2 | #import "JXHTTP.h"
3 |
4 | @implementation JXHTTPFileBody
5 |
6 | #pragma mark - Initialization
7 |
8 | - (instancetype)initWithFilePath:(NSString *)filePath contentType:(NSString *)contentType
9 | {
10 | if (self = [super init]) {
11 | self.filePath = filePath;
12 | self.httpContentType = contentType;
13 | }
14 | return self;
15 | }
16 |
17 | + (instancetype)withFilePath:(NSString *)filePath contentType:(NSString *)contentType
18 | {
19 | return [[self alloc] initWithFilePath:filePath contentType:contentType];
20 | }
21 |
22 | + (instancetype)withFilePath:(NSString *)filePath
23 | {
24 | return [self withFilePath:filePath contentType:nil];
25 | }
26 |
27 | #pragma mark -
28 |
29 | - (NSInputStream *)httpInputStream
30 | {
31 | return [[NSInputStream alloc] initWithFileAtPath:self.filePath];
32 | }
33 |
34 | - (long long)httpContentLength
35 | {
36 | if (![self.filePath length])
37 | return NSURLResponseUnknownLength;
38 |
39 | NSError *error = nil;
40 | NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:self.filePath error:&error];
41 | JXError(error);
42 |
43 | NSNumber *fileSize = [attributes objectForKey:NSFileSize];
44 | if (fileSize)
45 | return [fileSize longLongValue];
46 |
47 | return NSURLResponseUnknownLength;
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPFormEncodedBody.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPFormEncodedBody` conforms to and provides functionality for
3 | form-encoded request bodies (i.e., the type usually sent by browsers.)
4 |
5 | Reports its content type as `application/x-www-form-urlencoded; charset=utf-8`.
6 | */
7 |
8 | #import "JXHTTPRequestBody.h"
9 |
10 | @interface JXHTTPFormEncodedBody : NSObject
11 |
12 | /**
13 | A dictionary that will be form-encoded upon transmission.
14 | */
15 | @property (strong, readonly, nonatomic) NSMutableDictionary *dictionary;
16 |
17 | /**
18 | Creates a new `JXHTTPFormEncodedBody`.
19 |
20 | @see
21 |
22 | @param dictionary A dictionary that will be form-encoded upon transmission.
23 | @returns A request body.
24 | */
25 | + (instancetype)withDictionary:(NSDictionary *)dictionary;
26 |
27 | /**
28 | Creates a new `JXHTTPFormEncodedBody`.
29 |
30 | @see
31 |
32 | @param dictionary A dictionary that will be form-encoded upon transmission.
33 | @returns A request body.
34 | */
35 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPFormEncodedBody.m:
--------------------------------------------------------------------------------
1 | #import "JXHTTPFormEncodedBody.h"
2 | #import "JXURLEncoding.h"
3 |
4 | @interface JXHTTPFormEncodedBody ()
5 | @property (strong, nonatomic) NSMutableDictionary *dictionary;
6 | @end
7 |
8 | @implementation JXHTTPFormEncodedBody
9 |
10 | #pragma mark - Initialization
11 |
12 | - (instancetype)init
13 | {
14 | if (self = [super init]) {
15 | self.dictionary = [[NSMutableDictionary alloc] init];
16 | }
17 | return self;
18 | }
19 |
20 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary
21 | {
22 | if (self = [self init]) {
23 | self.dictionary = [[NSMutableDictionary alloc] initWithDictionary:dictionary];
24 | }
25 | return self;
26 | }
27 |
28 | + (instancetype)withDictionary:(NSDictionary *)dictionary
29 | {
30 | return [[self alloc] initWithDictionary:dictionary];
31 | }
32 |
33 | #pragma mark - Private Methods
34 |
35 | - (NSData *)requestData
36 | {
37 | return [[JXURLEncoding formEncodedDictionary:self.dictionary] dataUsingEncoding:NSUTF8StringEncoding];
38 | }
39 |
40 | #pragma mark -
41 |
42 | - (NSInputStream *)httpInputStream
43 | {
44 | return [[NSInputStream alloc] initWithData:[self requestData]];
45 | }
46 |
47 | - (NSString *)httpContentType
48 | {
49 | return @"application/x-www-form-urlencoded; charset=utf-8";
50 | }
51 |
52 | - (long long)httpContentLength
53 | {
54 | return [[self requestData] length];
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPJSONBody.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPJSONBody` conforms to and provides functionality for JSON
3 | POST request bodies.
4 |
5 | Reports its content type as `application/json; charset=utf-8`.
6 | */
7 |
8 | #import "JXHTTPRequestBody.h"
9 |
10 | @interface JXHTTPJSONBody : NSObject
11 |
12 | /**
13 | Creates a new `JXHTTPJSONBody`.
14 |
15 | @param data The UTF-8 data of a previously serialized JSON string.
16 | @returns A JSON request body.
17 | */
18 | + (instancetype)withData:(NSData *)data;
19 |
20 | /**
21 | Creates a new `JXHTTPJSONBody`.
22 |
23 | @param string A previously serialized JSON string.
24 | @returns A JSON request body.
25 | */
26 | + (instancetype)withString:(NSString *)string;
27 |
28 | /**
29 | Creates a new `JXHTTPJSONBody`.
30 |
31 | @param dictionaryOrArray A dictionary or array, which will be serialized into a JSON string.
32 | @returns A JSON request body.
33 | */
34 | + (instancetype)withJSONObject:(id)dictionaryOrArray;
35 |
36 | /**
37 | Creates a new `JXHTTPJSONBody`.
38 |
39 | @param data The UTF-8 data of a previously serialized JSON string.
40 | @returns A JSON request body.
41 | */
42 | - (instancetype)initWithData:(NSData *)data;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPJSONBody.m:
--------------------------------------------------------------------------------
1 | #import "JXHTTPJSONBody.h"
2 | #import "JXHTTP.h"
3 |
4 | @interface JXHTTPJSONBody ()
5 | @property (strong, nonatomic) NSData *requestData;
6 | @end
7 |
8 | @implementation JXHTTPJSONBody
9 |
10 | #pragma mark - Initialization
11 |
12 | - (instancetype)initWithData:(NSData *)data
13 | {
14 | if (self = [super init]) {
15 | self.requestData = data;
16 | }
17 | return self;
18 | }
19 |
20 | + (instancetype)withData:(NSData *)data
21 | {
22 | return [[self alloc] initWithData:data];
23 | }
24 |
25 | + (instancetype)withString:(NSString *)string
26 | {
27 | return [self withData:[string dataUsingEncoding:NSUTF8StringEncoding]];
28 | }
29 |
30 | + (instancetype)withJSONObject:(id)dictionaryOrArray
31 | {
32 | NSError *error = nil;
33 | NSData *data = [NSJSONSerialization dataWithJSONObject:dictionaryOrArray options:0 error:&error];
34 | JXError(error);
35 |
36 | return [self withData:data];
37 | }
38 |
39 | #pragma mark -
40 |
41 | - (NSInputStream *)httpInputStream
42 | {
43 | return [[NSInputStream alloc] initWithData:self.requestData];
44 | }
45 |
46 | - (NSString *)httpContentType
47 | {
48 | return @"application/json; charset=utf-8";
49 | }
50 |
51 | - (long long)httpContentLength
52 | {
53 | return [self.requestData length];
54 | }
55 |
56 | #pragma mark -
57 |
58 | - (void)httpOperationDidFinishLoading:(JXHTTPOperation *)operation
59 | {
60 | self.requestData = nil;
61 | }
62 |
63 | @end
64 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPMultipartBody.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPMultipartBody` conforms to and provides functionality for
3 | mulitpart MIME request bodies (with potentially multiple content types).
4 |
5 | File parts are streamed from disk using an `NSInputStream` and therefore memory
6 | efficient even in the case of very large files.
7 | */
8 |
9 | #import "JXHTTPRequestBody.h"
10 |
11 | @interface JXHTTPMultipartBody : NSObject
12 |
13 | /**
14 | The stream buffer size for the file input stream. In most cases you shouldn't need to
15 | change this, the 64K default is intended to match the output stream of `NSURLConnection`.
16 | */
17 | @property (assign, nonatomic) NSUInteger streamBufferLength;
18 |
19 | /**
20 | Creates a new `JXHTTPMultipartBody`.
21 |
22 | @param stringParameters A dictionary of keys and values that will be added as a text part.
23 | @returns A multipart request body.
24 | */
25 | + (instancetype)withDictionary:(NSDictionary *)stringParameters;
26 |
27 | /**
28 | Creates a new `JXHTTPMultipartBody`.
29 |
30 | @param stringParameters A dictionary of keys and values that will be added as a `text/plain` part.
31 | @returns A multipart request body.
32 | */
33 | - (instancetype)initWithDictionary:(NSDictionary *)stringParameters;
34 |
35 | /**
36 | Adds a new `text/plain` part with the specified key.
37 |
38 | @param string The value.
39 | @param key The key.
40 | */
41 | - (void)addString:(NSString *)string forKey:(NSString *)key;
42 |
43 | /**
44 | Adds a new `text/plain` part with the specified key and overwrites any existing value.
45 |
46 | @param string The value.
47 | @param key The key.
48 | */
49 | - (void)setString:(NSString *)string forKey:(NSString *)key;
50 |
51 | /**
52 | Adds a new data part with the specified content type.
53 |
54 | @param data The data.
55 | @param key The key.
56 | @param contentTypeOrNil The content type, or `nil` to default to `application/octet-stream`.
57 | @param fileNameOrNil A suggested file name for the recipient, ignored by most servers (safe to pass nil).
58 | */
59 | - (void)addData:(NSData *)data forKey:(NSString *)key contentType:(NSString *)contentTypeOrNil fileName:(NSString *)fileNameOrNil;
60 |
61 | /**
62 | Adds a new data part with the specified content type and overwrites any existing value.
63 |
64 | @param data The data.
65 | @param key The key.
66 | @param contentTypeOrNil The content type, or `nil` to default to `application/octet-stream`.
67 | @param fileNameOrNil A suggested file name for the recipient, ignored by most servers (safe to pass nil).
68 | */
69 | - (void)setData:(NSData *)data forKey:(NSString *)key contentType:(NSString *)contentTypeOrNil fileName:(NSString *)fileNameOrNil;
70 |
71 | /**
72 | Adds a new file part with the specified content type. The file will not be accessed until
73 | the connection begins but it must exist at the time it's added.
74 |
75 | @param filePath The local path of the file.
76 | @param key The key.
77 | @param contentTypeOrNil The content type, or `nil` to default to `application/octet-stream`.
78 | @param fileNameOrNil A suggested file name for the recipient, ignored by most servers (safe to pass nil).
79 | */
80 | - (void)addFile:(NSString *)filePath forKey:(NSString *)key contentType:(NSString *)contentTypeOrNil fileName:(NSString *)fileNameOrNil;
81 |
82 | /**
83 | Adds a new file part with the specified content type. The file will not be accessed until
84 | the connection begins but it must exist at the time it's added. Overwrites any existing value.
85 |
86 | @param filePath The local path of the file.
87 | @param key The key.
88 | @param contentTypeOrNil The content type, or `nil` to default to `application/octet-stream`.
89 | @param fileNameOrNil A suggested file name for the recipient, ignored by most servers (safe to pass nil).
90 | */
91 | - (void)setFile:(NSString *)filePath forKey:(NSString *)key contentType:(NSString *)contentTypeOrNil fileName:(NSString *)fileNameOrNil;
92 |
93 | @end
94 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPOperation+Convenience.h:
--------------------------------------------------------------------------------
1 | /**
2 | These methods and properties provide convenient access to the request and response objects of
3 | the underlying `NSURLConnection`. In most cases they simply pass through the property of the
4 | same name.
5 | */
6 |
7 | #import "JXHTTPOperation.h"
8 |
9 | @interface JXHTTPOperation (JXHTTPOperationConvenience)
10 |
11 | @property (assign, nonatomic) NSURLCacheStoragePolicy requestCachePolicy;
12 | @property (assign, nonatomic) BOOL requestShouldUsePipelining;
13 | @property (strong, nonatomic) NSURL *requestMainDocumentURL;
14 | @property (assign, nonatomic) NSTimeInterval requestTimeoutInterval;
15 | @property (assign, nonatomic) NSURLRequestNetworkServiceType requestNetworkServiceType;
16 | @property (strong, nonatomic) NSURL *requestURL;
17 | @property (strong, nonatomic) NSDictionary *requestHeaders;
18 | @property (strong, nonatomic) NSString *requestMethod;
19 | @property (assign, nonatomic) BOOL requestShouldHandleCookies;
20 |
21 | - (void)addValue:(NSString *)valueString forRequestHeader:(NSString *)headerFieldString;
22 | - (void)setValue:(NSString *)valueString forRequestHeader:(NSString *)headerFieldString;
23 |
24 | - (NSData *)responseData;
25 | - (NSString *)responseString;
26 | - (id)responseJSON;
27 | - (NSDictionary *)responseHeaders;
28 | - (NSInteger)responseStatusCode;
29 | - (NSString *)responseStatusString;
30 | - (long long)responseExpectedContentLength;
31 | - (NSString *)responseExpectedFileName;
32 | - (NSString *)responseMIMEType;
33 | - (NSString *)responseTextEncodingName;
34 | - (NSURL *)responseURL;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPOperation+Convenience.m:
--------------------------------------------------------------------------------
1 | #import "JXHTTPOperation+Convenience.h"
2 | #import "JXHTTP.h"
3 |
4 | @implementation JXHTTPOperation (JXHTTPOperationConvenience)
5 |
6 | #pragma mark - Request
7 |
8 | - (NSURLCacheStoragePolicy)requestCachePolicy
9 | {
10 | return self.request.cachePolicy;
11 | }
12 |
13 | - (void)setRequestCachePolicy:(NSURLCacheStoragePolicy)requestCachePolicy
14 | {
15 | self.request.cachePolicy = requestCachePolicy;
16 | }
17 |
18 | - (BOOL)requestShouldUsePipelining
19 | {
20 | return self.request.HTTPShouldUsePipelining;
21 | }
22 |
23 | - (void)setRequestShouldUsePipelining:(BOOL)requestShouldUsePipelining
24 | {
25 | self.request.HTTPShouldUsePipelining = requestShouldUsePipelining;
26 | }
27 |
28 | - (NSURL *)requestMainDocumentURL
29 | {
30 | return self.request.mainDocumentURL;
31 | }
32 |
33 | - (void)setRequestMainDocumentURL:(NSURL *)requestMainDocumentURL
34 | {
35 | self.request.mainDocumentURL = requestMainDocumentURL;
36 | }
37 |
38 | - (NSTimeInterval)requestTimeoutInterval
39 | {
40 | return self.request.timeoutInterval;
41 | }
42 |
43 | - (void)setRequestTimeoutInterval:(NSTimeInterval)requestTimeoutInterval
44 | {
45 | self.request.timeoutInterval = requestTimeoutInterval;
46 | }
47 |
48 | - (NSURLRequestNetworkServiceType)requestNetworkServiceType
49 | {
50 | return self.request.networkServiceType;
51 | }
52 |
53 | - (void)setRequestNetworkServiceType:(NSURLRequestNetworkServiceType)requestNetworkServiceType
54 | {
55 | self.request.networkServiceType = requestNetworkServiceType;
56 | }
57 |
58 | - (NSURL *)requestURL
59 | {
60 | return self.request.URL;
61 | }
62 |
63 | - (void)setRequestURL:(NSURL *)requestURL
64 | {
65 | self.request.URL = requestURL;
66 | }
67 |
68 | - (NSDictionary *)requestHeaders
69 | {
70 | return [self.request allHTTPHeaderFields];
71 | }
72 |
73 | - (void)setRequestHeaders:(NSDictionary *)requestHeaders
74 | {
75 | [self.request setAllHTTPHeaderFields:requestHeaders];
76 | }
77 |
78 | - (NSString *)requestMethod
79 | {
80 | return self.request.HTTPMethod;
81 | }
82 |
83 | - (void)setRequestMethod:(NSString *)requestMethod
84 | {
85 | self.request.HTTPMethod = requestMethod;
86 | }
87 |
88 | - (BOOL)requestShouldHandleCookies
89 | {
90 | return self.request.HTTPShouldHandleCookies;
91 | }
92 |
93 | - (void)setRequestShouldHandleCookies:(BOOL)requestShouldHandleCookies
94 | {
95 | self.request.HTTPShouldHandleCookies = requestShouldHandleCookies;
96 | }
97 |
98 | - (void)addValue:(NSString *)valueString forRequestHeader:(NSString *)headerFieldString
99 | {
100 | [self.request addValue:valueString forHTTPHeaderField:headerFieldString];
101 | }
102 |
103 | - (void)setValue:(NSString *)valueString forRequestHeader:(NSString *)headerFieldString
104 | {
105 | [self.request setValue:valueString forHTTPHeaderField:headerFieldString];
106 | }
107 |
108 | #pragma mark - Response
109 |
110 | - (NSData *)responseData
111 | {
112 | NSData *data = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
113 | if (data)
114 | return data;
115 |
116 | return [NSData dataWithContentsOfMappedFile:self.responseDataFilePath];
117 | }
118 |
119 | - (NSString *)responseString
120 | {
121 | return [[NSString alloc] initWithData:[self responseData] encoding:NSUTF8StringEncoding];
122 | }
123 |
124 | - (id)responseJSON
125 | {
126 | NSData *data = [self responseData];
127 | if (!data)
128 | return nil;
129 |
130 | NSError *error = nil;
131 | id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
132 | JXError(error);
133 |
134 | return json;
135 | }
136 |
137 | - (NSDictionary *)responseHeaders
138 | {
139 | return [(NSHTTPURLResponse *)self.response allHeaderFields];
140 | }
141 |
142 | - (NSInteger)responseStatusCode
143 | {
144 | return [(NSHTTPURLResponse *)self.response statusCode];
145 | }
146 |
147 | - (NSString *)responseStatusString
148 | {
149 | return [NSHTTPURLResponse localizedStringForStatusCode:[self responseStatusCode]];
150 | }
151 |
152 | - (long long)responseExpectedContentLength
153 | {
154 | return self.response.expectedContentLength;
155 | }
156 |
157 | - (NSString *)responseExpectedFileName
158 | {
159 | return self.response.suggestedFilename;
160 | }
161 |
162 | - (NSString *)responseMIMEType
163 | {
164 | return self.response.MIMEType;
165 | }
166 |
167 | - (NSString *)responseTextEncodingName
168 | {
169 | return self.response.textEncodingName;
170 | }
171 |
172 | - (NSURL *)responseURL
173 | {
174 | return self.response.URL;
175 | }
176 |
177 | @end
178 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPOperation.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPOperation` adds many features to , including blocks
3 | and delegate methods via the protocol. Blocks are
4 | performed serially on a private background queue unless
5 | is set to `YES`.
6 |
7 | can be used to group multiple operations for progress tracking.
8 |
9 | Request data (i.e., POST bodies) can be supplied with an `NSInputStream` via the
10 | property, which takes any object conforming to the
11 | protocol. The most common are premade:
12 |
13 | - (browser-style form encoding)
14 | - (multipart streaming from disk or memory)
15 | - (single part streaming from disk)
16 | - (JSON from collection objects or string)
17 | - (raw request data)
18 |
19 | In addition, this family of classes makes use of to escape strings
20 | and to provide easier access to the underlying
21 | properties of request and response objects.
22 |
23 | On iOS, the system network activity indicator is updated by default. It waits on a
24 | 0.25 second timer from the end of the last operation to prevent flickering.
25 |
26 | ## Examples ##
27 |
28 | ### Basic Operation ###
29 |
30 | JXHTTPOperation *op = [JXHTTPOperation withURLString:@"http://jxhttp.com/"];
31 | op.didFinishLoadingBlock = ^(JXHTTPOperation *op) {
32 | NSLog(@"some html: %@", op.responseString);
33 | };
34 |
35 | [[JXHTTPOperationQueue sharedQueue] addOperation:op];
36 |
37 | */
38 |
39 | #import "JXURLConnectionOperation.h"
40 | #import "JXHTTPOperationDelegate.h"
41 | #import "JXHTTPRequestBody.h"
42 |
43 | typedef void (^JXHTTPBlock)(JXHTTPOperation *operation);
44 | typedef NSCachedURLResponse * (^JXHTTPCacheBlock)(JXHTTPOperation *operation, NSCachedURLResponse *response);
45 | typedef NSURLRequest * (^JXHTTPRedirectBlock)(JXHTTPOperation *operation, NSURLRequest *request, NSURLResponse *response);
46 |
47 | @interface JXHTTPOperation : JXURLConnectionOperation
48 |
49 | /// @name Core
50 |
51 | /**
52 | An optional, non-retained object conforming to the protocol.
53 |
54 | Safe to access from any thread at any time.
55 |
56 | @warning Delegate methods will be called on a background thread. No other
57 | guarantees are made about thread continuity.
58 | */
59 | @property (weak) NSObject *delegate;
60 |
61 | /**
62 | An optional request body object. The protocol extends ,
63 | and has an opportunity to respond to the same messages immediately after the .
64 |
65 | Safe to access from any thread at any time, should only be changed before operation start.
66 | */
67 | @property (strong) NSObject *requestBody;
68 |
69 | /**
70 | A string guaranteed to be unique for the lifetime of the application process, useful
71 | for keying operations stored in a collection.
72 |
73 | Safe to access from any thread at any time.
74 | */
75 | @property (strong, readonly) NSString *uniqueString;
76 |
77 | /**
78 | A convenience property for creating an `NSOutputStream` that streams response data to disk.
79 | If this property is nil when the operation starts the `outputStream` property is used instead,
80 | which defaults to in-memory storage.
81 |
82 | @warning Unlike most properties of `JXHTTPOperation`, `responseDataFilePath` should not be accessed
83 | from mulitiple threads simultaneously and should only be changed before operation start.
84 | */
85 | @property (copy, nonatomic) NSString *responseDataFilePath;
86 |
87 | /**
88 | A user-supplied object retained for the lifetime of the operation.
89 |
90 | Safe to access and change from any thread at any time.
91 | */
92 | @property (strong) id userObject;
93 |
94 | /// @name Security
95 |
96 | @property (strong, readonly) NSURLAuthenticationChallenge *authenticationChallenge;
97 | @property (strong) NSURLCredential *credential;
98 | @property (assign) BOOL useCredentialStorage;
99 | @property (assign) BOOL trustAllHosts;
100 | @property (copy) NSArray *trustedHosts;
101 | @property (copy) NSString *username;
102 | @property (copy) NSString *password;
103 |
104 | /// @name Progress
105 |
106 | /**
107 | A number between 0.0 and 1.0 indicating the download progress of the response,
108 | or `NSURLResponseUnknownLength` if the expected content length is unknown.
109 |
110 | Safe to access from any thread at any time.
111 | */
112 | @property (strong, readonly) NSNumber *downloadProgress;
113 |
114 | /**
115 | A number between 0.0 and 1.0 indicating the upload progress of the response,
116 | or `NSURLResponseUnknownLength` if the expected content length is unknown.
117 |
118 | Safe to access from any thread at any time.
119 | */
120 | @property (strong, readonly) NSNumber *uploadProgress;
121 |
122 | /**
123 | If `YES`, the system network activity indicator is updated (iOS only). Defaults to `YES`.
124 | A timer is used to prevent flickering.
125 |
126 | Safe to access and change from any thread at any time.
127 | */
128 | @property (assign) BOOL updatesNetworkActivityIndicator;
129 |
130 | /// @name Timing
131 |
132 | /**
133 | The start date of the operation or `nil` if the operation has not started.
134 |
135 | Safe to access from any thread at any time.
136 | */
137 | @property (strong, readonly) NSDate *startDate;
138 |
139 | /**
140 | The finish date of the operation or `nil` if the operation has not finished.
141 |
142 | Safe to access from any thread at any time.
143 | */
144 | @property (strong, readonly) NSDate *finishDate;
145 |
146 | /**
147 | The number of seconds elapsed since the operation started, 0.0 if it has not.
148 |
149 | Safe to access from any thread at any time.
150 | */
151 | @property (readonly) NSTimeInterval elapsedSeconds;
152 |
153 | /// @name Blocks
154 |
155 | /**
156 | If `YES`, blocks are dispatched to the main queue and run on the main thread.
157 |
158 | Defaults to `NO`, blocks are run a private serial dispatch queue.
159 |
160 | Safe to access and change from any thread at any time.
161 | */
162 | @property (assign) BOOL performsBlocksOnMainQueue;
163 |
164 | /**
165 | Performed at the very start of the operation, before the connection object is created.
166 |
167 | Safe to access and change from any thread at any time.
168 |
169 | @see
170 | */
171 | @property (copy) JXHTTPBlock willStartBlock;
172 |
173 | /**
174 | Performed when the underlying `NSURLConnection` requires a new, unopened stream
175 | for the when a retransmission is necessary.
176 |
177 | Safe to access and change from any thread at any time.
178 |
179 | @warning For notification purposes only, do not use this block to supply the stream.
180 |
181 | @see
182 | */
183 | @property (copy) JXHTTPBlock willNeedNewBodyStreamBlock;
184 |
185 | /**
186 | Performed when the underlying `NSURLConnection` receives a request for authentication.
187 |
188 | Safe to access and change from any thread at any time.
189 |
190 | @warning For notification purposes only, do not use this block to supply the credential.
191 | @see
192 | */
193 | @property (copy) JXHTTPBlock willSendRequestForAuthenticationChallengeBlock;
194 |
195 | /**
196 | Performed immediately after the underlying `NSURLConnection` begins.
197 |
198 | Safe to access and change from any thread at any time.
199 |
200 | @see
201 | */
202 | @property (copy) JXHTTPBlock didStartBlock;
203 |
204 | /**
205 | Performed immediately after the underlying `NSURLConnection` receives a response.
206 |
207 | Safe to access and change from any thread at any time.
208 |
209 | @see
210 | */
211 | @property (copy) JXHTTPBlock didReceiveResponseBlock;
212 |
213 | /**
214 | Performed every time the underlying `NSURLConnection` receives response data.
215 |
216 | Safe to access and change from any thread at any time.
217 |
218 | @see
219 | */
220 | @property (copy) JXHTTPBlock didReceiveDataBlock;
221 |
222 | /**
223 | Performed every time the underlying `NSURLConnection` sends request data.
224 |
225 | Safe to access and change from any thread at any time.
226 |
227 | @see
228 | */
229 | @property (copy) JXHTTPBlock didSendDataBlock;
230 |
231 | /**
232 | Performed when the underlying `NSURLConnection` finishes loading successfully.
233 |
234 | Safe to access and change from any thread at any time.
235 |
236 | @see
237 | */
238 | @property (copy) JXHTTPBlock didFinishLoadingBlock;
239 |
240 | /**
241 | Performed when the underlying `NSURLConnection` fails to load. The `error` property
242 | is available for inspection.
243 |
244 | Safe to access and change from any thread at any time.
245 |
246 | @see
247 | */
248 | @property (copy) JXHTTPBlock didFailBlock;
249 |
250 | /**
251 | TKTK
252 |
253 | Safe to access and change from any thread at any time.
254 |
255 | @see
256 | */
257 | @property (copy) JXHTTPCacheBlock willCacheResponseBlock;
258 |
259 | /**
260 | TKTK
261 |
262 | Safe to access and change from any thread at any time.
263 |
264 | @see
265 | */
266 | @property (copy) JXHTTPRedirectBlock willSendRequestRedirectBlock;
267 |
268 | /// @name Initialization
269 |
270 | /**
271 | Creates a new `JXHTTPOperation` with the specified URL.
272 |
273 | @param urlString The URL to request.
274 | @returns An operation.
275 | */
276 | + (instancetype)withURLString:(NSString *)urlString;
277 |
278 | /**
279 | Creates a new `JXHTTPOperation` with the specified URL and query parameters,
280 | escaped via .
281 |
282 | @param urlString The URL to request.
283 | @param parameters A dictionary of keys and values to form the query string.
284 | @returns An operation.
285 | */
286 | + (instancetype)withURLString:(NSString *)urlString queryParameters:(NSDictionary *)parameters;
287 |
288 | @end
289 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPOperationDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPOperationDelegate` is a protocol that allows any object to receive synchronous callbacks about
3 | the progress of a `JXHTTPOperation` and optionally influence its execution.
4 |
5 | These methods may be called from different threads.
6 | */
7 | @class JXHTTPOperation;
8 |
9 | @protocol JXHTTPOperationDelegate
10 |
11 | @optional
12 |
13 | /**
14 | Called at the very beginning of the operation, before the connection starts and before the
15 | request body is setup.
16 |
17 | @param operation The operation.
18 | */
19 | - (void)httpOperationWillStart:(JXHTTPOperation *)operation;
20 |
21 | /**
22 | Called when the connection needs a new, unopened body stream.
23 |
24 | @param operation The operation.
25 | */
26 | - (void)httpOperationWillNeedNewBodyStream:(JXHTTPOperation *)operation;
27 |
28 | /**
29 | Called when the underlying `NSURLConnection` receives `willSendRequestForAuthenticationChallenge:`,
30 | see the `NSURLConnectionDelegate` docs for more information.
31 |
32 | The `NSURLAuthenticationChallenge` is available for inspection via the `authenticateChallenge`
33 | property of the operation. To supply your own `NSURLCredential` in response to the challenge, set
34 | the `credential` property before this method exits.
35 |
36 | In most cases, it's easier to respond to HTTP basic auth challenges via the `username` and `password`
37 | properties, which can be set before the operation begins instead of using this callback.
38 |
39 | Similarly, SSL challenges can be met with the `trustedHosts` or `trustAllHosts` properties.
40 |
41 | If this method is implemented and no `credential` is supplied, the operation attempts to proceed
42 | by calling `continueWithoutCredentialForAuthenticationChallenge:` on the sender.
43 |
44 | @param operation The operation.
45 | */
46 | - (void)httpOperationWillSendRequestForAuthenticationChallenge:(JXHTTPOperation *)operation;
47 |
48 | /**
49 | Called just after the connection starts. At this point all streams will be open.
50 |
51 | @param operation The operation.
52 | */
53 | - (void)httpOperationDidStart:(JXHTTPOperation *)operation;
54 |
55 | /**
56 | Called when the connection receives a response (zero or once per operation).
57 |
58 | @param operation The operation.
59 | */
60 | - (void)httpOperationDidReceiveResponse:(JXHTTPOperation *)operation;
61 |
62 | /**
63 | Called periodically as the connection receives data.
64 |
65 | @param operation The operation.
66 | */
67 | - (void)httpOperationDidReceiveData:(JXHTTPOperation *)operation;
68 |
69 | /**
70 | Called periodically as the connection sends data.
71 |
72 | @param operation The operation.
73 | */
74 | - (void)httpOperationDidSendData:(JXHTTPOperation *)operation;
75 |
76 | /**
77 | Called when the connection finishes loading data, but before the operation has completed.
78 |
79 | @param operation The operation.
80 | */
81 | - (void)httpOperationDidFinishLoading:(JXHTTPOperation *)operation;
82 |
83 | /**
84 | Called when the operation fails (zero or once per operation).
85 |
86 | @param operation The operation.
87 | */
88 | - (void)httpOperationDidFail:(JXHTTPOperation *)operation;
89 |
90 | /**
91 | Called before the operation caches a response. The response can be modified before storage.
92 |
93 | Returning nil will prevent the request from being cached. See the `NSURLConnectionDataDelegate`
94 | docs for more information.
95 |
96 | @param operation The operation.
97 | @param cachedResponse The response to be cached.
98 | @returns A modified cache response, the original cache response, or nil if no caching should occur.
99 | */
100 | - (NSCachedURLResponse *)httpOperation:(JXHTTPOperation *)operation willCacheResponse:(NSCachedURLResponse *)cachedResponse;
101 |
102 | /**
103 | Called before the underlying `NSURLConnection` changes URLs in response to a redirection.
104 | May be called multiple times.
105 |
106 | See the `NSURLConnectionDataDelegate` docs for more information.
107 |
108 | @param operation The operation.
109 | @param request The proposed redirect request.
110 | @param redirectResponse The response that caused the direct (may be nil).
111 | @returns A new request for redirection, the original request to continue redirection,or nil to prevent redirection.
112 | */
113 | - (NSURLRequest *)httpOperation:(JXHTTPOperation *)operation willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
114 | @end
115 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPOperationQueue.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPOperationQueue` is an `NSOperationQueue` subclass and can be used to group
3 | multiple instances of for progress tracking, timing, or cancellation.
4 | It provides blocks and delegate methods via the protocol.
5 |
6 | Any `NSOperation` subclass can be safely added to this queue; classes other than
7 | receive no special treatment.
8 |
9 | Progress and byte count properties are reset every time a new operation is added when
10 | the queue is empty.
11 |
12 | ## Example ##
13 |
14 | JXHTTPOperationQueue *queue = [[JXHTTPOperationQueue alloc] init];
15 |
16 | queue.didFinishBlock = ^(JXHTTPOperationQueue *queue) {
17 | NSLog(@"queue finished at %@", queue.finishDate);
18 | NSLog(@"total bytes downloaded: %@", queue.bytesDownloaded);
19 | };
20 |
21 | for (NSUInteger i = 0; i < 10; i++) {
22 | JXHTTPOperation *op = [JXHTTPOperation withURLString:@"http://jxhttp.com/"];
23 |
24 | op.didFinishLoadingBlock = ^(JXHTTPOperation *op) {
25 | NSLog(@"operation %d finished loading at %@", i, op.finishDate);
26 | };
27 |
28 | [queue addOperation:op];
29 | }
30 | */
31 |
32 | #import "JXHTTPOperationQueueDelegate.h"
33 |
34 | typedef void (^JXHTTPQueueBlock)(JXHTTPOperationQueue *queue);
35 |
36 | @interface JXHTTPOperationQueue : NSOperationQueue
37 |
38 | /// @name Core
39 |
40 | /**
41 | The operation's delegate, conforming to .
42 |
43 | Safe to access from any thread at any time.
44 | */
45 | @property (weak) NSObject *delegate;
46 |
47 | /**
48 | A string guaranteed to be unique for the lifetime of the application process.
49 |
50 | Safe to access from any thread at any time.
51 | */
52 | @property (strong, readonly) NSString *uniqueString;
53 |
54 | /// @name Progress
55 |
56 | /**
57 | A number between 0 and 1 representing the percentage of download progress.
58 |
59 | Safe to access from any thread at any time.
60 | */
61 | @property (strong, readonly) NSNumber *downloadProgress;
62 |
63 | /**
64 | A number between 0 and 1 representing the percentage of upload progress.
65 |
66 | Safe to access from any thread at any time.
67 | */
68 | @property (strong, readonly) NSNumber *uploadProgress;
69 |
70 | /**
71 | The total number of bytes downloaded.
72 |
73 | Safe to access from any thread at any time.
74 | */
75 | @property (strong, readonly) NSNumber *bytesDownloaded;
76 |
77 | /**
78 | The total number of bytes uploaded.
79 |
80 | Safe to access from any thread at any time.
81 | */
82 | @property (strong, readonly) NSNumber *bytesUploaded;
83 |
84 | /**
85 | The total number of bytes expected to be downloaded.
86 |
87 | Safe to access from any thread at any time.
88 | */
89 | @property (strong, readonly) NSNumber *expectedDownloadBytes;
90 |
91 | /**
92 | The total number of bytes expected to be uploaded.
93 |
94 | Safe to access from any thread at any time.
95 | */
96 | @property (strong, readonly) NSNumber *expectedUploadBytes;
97 |
98 | /// @name Timing
99 |
100 | /**
101 | The date the request started.
102 |
103 | Safe to access from any thread at any time.
104 | */
105 | @property (strong, readonly) NSDate *startDate;
106 |
107 | /**
108 | The date the request finished (or failed).
109 |
110 | Safe to access from any thread at any time.
111 | */
112 | @property (strong, readonly) NSDate *finishDate;
113 |
114 | /**
115 | The number of seconds elapsed between the and the (or the
116 | current date if the request is still running). `0.0` if the request has not started.
117 |
118 | Safe to access from any thread at any time.
119 | */
120 | @property (readonly) NSTimeInterval elapsedSeconds;
121 |
122 | /// @name Blocks
123 |
124 | @property (assign) BOOL performsBlocksOnMainQueue;
125 | @property (copy) JXHTTPQueueBlock willStartBlock;
126 | @property (copy) JXHTTPQueueBlock willFinishBlock;
127 | @property (copy) JXHTTPQueueBlock didStartBlock;
128 | @property (copy) JXHTTPQueueBlock didUploadBlock;
129 | @property (copy) JXHTTPQueueBlock didDownloadBlock;
130 | @property (copy) JXHTTPQueueBlock didMakeProgressBlock;
131 | @property (copy) JXHTTPQueueBlock didFinishBlock;
132 |
133 | /**
134 | A singleton queue with a default `maxConcurrentOperationCount` of `4`.
135 |
136 | @returns The shared HTTP operation queue.
137 | */
138 | + (instancetype)sharedQueue;
139 |
140 | @end
141 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPOperationQueueDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPOperationQueueDelegate` is a protocol that allows any object to receive synchronous
3 | callbacks about the progress of a `JXHTTPOperationQueue`.
4 |
5 | These methods may be called from different threads.
6 | */
7 |
8 | @class JXHTTPOperationQueue;
9 |
10 | @protocol JXHTTPOperationQueueDelegate
11 | @optional
12 |
13 | /**
14 | Called when the queue adds an operation from an empty state.
15 |
16 | @param queue The queue.
17 | */
18 | - (void)httpOperationQueueWillStart:(JXHTTPOperationQueue *)queue;
19 |
20 | /**
21 | Called when the queue has completed all operations.
22 |
23 | @param queue The queue.
24 | */
25 | - (void)httpOperationQueueWillFinish:(JXHTTPOperationQueue *)queue;
26 |
27 | /**
28 | Called just after the first operation is added to the queue.
29 |
30 | @param queue The queue.
31 | */
32 | - (void)httpOperationQueueDidStart:(JXHTTPOperationQueue *)queue;
33 |
34 | /**
35 | Called periodically as operations in the queue upload data.
36 |
37 | @param queue The queue.
38 | */
39 | - (void)httpOperationQueueDidUpload:(JXHTTPOperationQueue *)queue;
40 |
41 | /**
42 | Called periodically as operations in the queue download data.
43 |
44 | @param queue The queue.
45 | */
46 | - (void)httpOperationQueueDidDownload:(JXHTTPOperationQueue *)queue;
47 |
48 | /**
49 | Called periodically as operations in the queue download or upload data.
50 |
51 | @param queue The queue.
52 | */
53 | - (void)httpOperationQueueDidMakeProgress:(JXHTTPOperationQueue *)queue;
54 |
55 | /**
56 | Called when the last operation in the queue finishes.
57 |
58 | @param queue The queue.
59 | */
60 | - (void)httpOperationQueueDidFinish:(JXHTTPOperationQueue *)queue;
61 | @end
62 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXHTTPRequestBody.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXHTTPRequestBody` is a protocol that allows any object to provide request body data for a
3 | `JXHTTPOperation`. Conforming objects also receive the standard
4 | calls (if implemented). This allows, for example, last minute creation of an input stream
5 | when the operation starts.
6 |
7 | All methods are guaranteed to be called serially from the same thread.
8 | */
9 |
10 | #import "JXHTTPOperationDelegate.h"
11 |
12 | @protocol JXHTTPRequestBody
13 | @required
14 |
15 | /**
16 | A stream that will supply the data for the request body section of an HTTP request.
17 |
18 | @warning This method may be called multiple times and must return a new, unopened stream.
19 |
20 | @returns An input stream.
21 | */
22 | - (NSInputStream *)httpInputStream;
23 |
24 | /**
25 | A string that represents the MIME content type of the request data. If nil, defaults to
26 | `application/octet-stream`.
27 |
28 | @returns A string.
29 | */
30 | - (NSString *)httpContentType;
31 |
32 | /**
33 | The expected length of the request data, used to calculate upload progress. If unknown
34 | this method is expected to return `NSURLResponseUnknownLength`.
35 |
36 | @returns An integer.
37 | */
38 | - (long long)httpContentLength;
39 | @end
40 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXOperation.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXOperation` is an abstract `NSOperation` subclass that implements all the
3 | methods necessary for what Apple calls "concurrent" operations. See the sections
4 | titled _Subclassing Notes_ and _Multicore Considerations_ in the `NSOperation`
5 | class reference, this class does all of it for you.
6 |
7 | The main advantage of concurrent operations is that they allow for the use of
8 | asynchronous APIs. Normally, when the `main` method of an `NSOperation` exits,
9 | the operation marks itself as finished and deallocation is imminent. In a
10 | concurrent operation, nothing happens when `main` exits and it's up to you to
11 | manually report that the operation has finished (via KVO). In the meantime you
12 | can wait for delegate callbacks or any other asynchronous event.
13 |
14 | Unfortunately, `NSOperation` has some quirks and ensuring thread safety as
15 | the operation changes state can be tricky. `JXOperation` makes it easier by
16 | providing a simple method that can be called at any time from any
17 | thread, without worrying about the operation's current state.
18 |
19 | Heavily inspired by Dave Dribin, and building on his work detailed here:
20 |
21 |
22 |
23 |
24 | */
25 |
26 | @interface JXOperation : NSOperation
27 |
28 | /// @name Operation State
29 |
30 | /**
31 | `YES` while the operation is executing, otherwise `NO`.
32 |
33 | Safe to access from any thread at any time.
34 | */
35 | @property (assign, readonly) BOOL isExecuting;
36 |
37 | /**
38 | `YES` if the operation has finished, otherwise `NO`.
39 |
40 | Safe to access from any thread at any time.
41 | */
42 | @property (assign, readonly) BOOL isFinished;
43 |
44 | /**
45 | Upon being set to `YES`, retrieves a `UIBackgroundTaskIdentifier` to allow the
46 | operation to continue running when the application enters the background.
47 |
48 | Safe to access from any thread at any time.
49 |
50 | @warning Changing this property to `YES` after the operation has started will
51 | have no effect. Changing it to `NO` will discontinue background execution.
52 | */
53 | @property (assign) BOOL continuesInAppBackground;
54 |
55 | /// @name Initialization
56 |
57 | /**
58 | Creates a new operation.
59 |
60 | @returns An operation.
61 | */
62 | + (instancetype)operation;
63 |
64 | /// @name Starting & Finishing
65 |
66 | /**
67 | Starts the operation and blocks the calling thread until it has finished.
68 | */
69 | - (void)startAndWaitUntilFinished;
70 |
71 | /**
72 | Called just before the operation finishes on the same thread (including as a result of
73 | being cancelled). Guaranteed to be called only once. Subclasses should override this
74 | method (and call `super`) instead of overriding .
75 |
76 | @warning Do not call this method yourself.
77 | */
78 | - (void)willFinish;
79 |
80 | /**
81 | Ends the operation and marks it for removal from its queue (if applicable).
82 | Subclasses must eventually call this method to cause the operation to finish,
83 | typically after the work performed in `main` is complete.
84 |
85 | This method is safe to call multiple times from any thread at any time, including
86 | before the operation has started.
87 |
88 | @warning To ensure thread saftey, do not override this method (use
89 | instead). After the operation has finished do not attempt to access any of its
90 | properties as it may have been released by a queue or other retaining object from a
91 | different thread.
92 | */
93 | - (void)finish;
94 |
95 | @end
96 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXOperation.m:
--------------------------------------------------------------------------------
1 | #import "JXOperation.h"
2 |
3 | @interface JXOperation ()
4 |
5 | @property (assign) BOOL isExecuting;
6 | @property (assign) BOOL isFinished;
7 |
8 | #if OS_OBJECT_USE_OBJC
9 | @property (strong) dispatch_queue_t stateQueue;
10 | #else
11 | @property (assign) dispatch_queue_t stateQueue;
12 | #endif
13 |
14 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
15 | @property (assign) UIBackgroundTaskIdentifier backgroundTaskID;
16 | #endif
17 |
18 | @end
19 |
20 | @implementation JXOperation
21 |
22 | #pragma mark - Initialization
23 |
24 | - (void)dealloc
25 | {
26 | [self endAppBackgroundTask];
27 |
28 | #if !OS_OBJECT_USE_OBJC
29 | dispatch_release(_stateQueue);
30 | _stateQueue = NULL;
31 | #endif
32 | }
33 |
34 | - (instancetype)init
35 | {
36 | if (self = [super init]) {
37 | NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p.state", NSStringFromClass([self class]), self];
38 | self.stateQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL);
39 |
40 | self.isExecuting = NO;
41 | self.isFinished = NO;
42 | self.continuesInAppBackground = NO;
43 |
44 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
45 | self.backgroundTaskID = UIBackgroundTaskInvalid;
46 | #endif
47 | }
48 | return self;
49 | }
50 |
51 | + (instancetype)operation
52 | {
53 | return [[self alloc] init];
54 | }
55 |
56 | #pragma mark - NSOperation
57 |
58 | - (void)start
59 | {
60 | __block BOOL shouldStart = YES;
61 |
62 | dispatch_sync(self.stateQueue, ^{
63 | if (![self isReady] || [self isCancelled] || self.isExecuting || self.isFinished) {
64 | shouldStart = NO;
65 | } else {
66 | [self willChangeValueForKey:@"isExecuting"];
67 | self.isExecuting = YES;
68 | [self didChangeValueForKey:@"isExecuting"];
69 |
70 | if (self.continuesInAppBackground)
71 | [self startAppBackgroundTask];
72 | }
73 | });
74 |
75 | if (!shouldStart || [self isCancelled])
76 | return;
77 |
78 | @autoreleasepool {
79 | [self main];
80 | }
81 | }
82 |
83 | - (void)main
84 | {
85 | NSAssert(NO, @"subclasses must implement and eventually call finish", nil);
86 | }
87 |
88 | #pragma mark - Public Methods
89 |
90 | - (BOOL)isConcurrent
91 | {
92 | return YES;
93 | }
94 |
95 | - (void)cancel
96 | {
97 | [super cancel];
98 |
99 | [self finish];
100 | }
101 |
102 | - (void)willFinish
103 | {
104 | [self endAppBackgroundTask];
105 | }
106 |
107 | - (void)finish
108 | {
109 | dispatch_sync(self.stateQueue, ^{
110 | if (self.isFinished)
111 | return;
112 |
113 | [self willFinish];
114 |
115 | if (self.isExecuting) {
116 | [self willChangeValueForKey:@"isExecuting"];
117 | [self willChangeValueForKey:@"isFinished"];
118 | self.isExecuting = NO;
119 | self.isFinished = YES;
120 | [self didChangeValueForKey:@"isExecuting"];
121 | [self didChangeValueForKey:@"isFinished"];
122 | } else if (!self.isFinished) {
123 | self.isExecuting = NO;
124 | self.isFinished = YES;
125 | }
126 | });
127 | }
128 |
129 | - (void)startAndWaitUntilFinished
130 | {
131 | NSOperationQueue *tempQueue = [[NSOperationQueue alloc] init];
132 | [tempQueue addOperation:self];
133 | [tempQueue waitUntilAllOperationsAreFinished];
134 | }
135 |
136 | #pragma mark - Private Methods
137 |
138 | - (void)startAppBackgroundTask
139 | {
140 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
141 |
142 | if (self.backgroundTaskID != UIBackgroundTaskInvalid || [self isCancelled])
143 | return;
144 |
145 | __weak __typeof(self) weakSelf = self;
146 |
147 | dispatch_async(dispatch_get_main_queue(), ^{
148 | __typeof(weakSelf) strongSelf = weakSelf;
149 |
150 | if (!strongSelf || [strongSelf isCancelled] || strongSelf.isFinished)
151 | return;
152 |
153 | UIBackgroundTaskIdentifier taskID = UIBackgroundTaskInvalid;
154 | taskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
155 | [[UIApplication sharedApplication] endBackgroundTask:taskID];
156 | }];
157 |
158 | strongSelf.backgroundTaskID = taskID;
159 | });
160 |
161 | #endif
162 | }
163 |
164 | - (void)endAppBackgroundTask
165 | {
166 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
167 |
168 | UIBackgroundTaskIdentifier taskID = self.backgroundTaskID;
169 | if (taskID == UIBackgroundTaskInvalid)
170 | return;
171 |
172 | self.backgroundTaskID = UIBackgroundTaskInvalid;
173 |
174 | dispatch_async(dispatch_get_main_queue(), ^{
175 | [[UIApplication sharedApplication] endBackgroundTask:taskID];
176 | });
177 |
178 | #endif
179 | }
180 |
181 | @end
182 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXURLConnectionOperation.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXURLConnectionOperation` is a subclass that encapsulates an
3 | `NSURLConnection`. It implements a basic set of delegate methods for writing
4 | response data to an `NSOutputStream` and counting the bytes transferred.
5 |
6 | All connections and streams are scheduled on the runloop of a
7 | that never exits. This is preferable to using the runloop of a thread provided
8 | by a queue because GCD manages its threads dynamically and there's no guarantee
9 | about the lifetime of a GCD thread. There is also evidence that manipulating
10 | the runloop of a GCD thread confuses the GCD scheduler. For more discussion:
11 |
12 |
13 |
14 | From the _Concurrency Programming Guide_: "Although you can obtain information
15 | about the underlying thread running a task, it is better to avoid doing so."
16 | And so we provide our own thread.
17 |
18 | ## Example ##
19 |
20 | Although `JXURLConnectionOperation` is essentially a building block towards
21 | it can be used effectively (if tediously) on its own:
22 |
23 | NSURL *url = [[NSURL alloc] initWithString:@"http://jxhttp.com/"];
24 | JXURLConnectionOperation *op = [[JXURLConnectionOperation alloc] initWithURL:url];
25 | [op startAndWaitUntilFinished];
26 |
27 | NSData *responseData = [op.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
28 | NSString *someHTML = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
29 | NSLog(@"%@", someHTML);
30 | */
31 |
32 | #import "JXOperation.h"
33 |
34 | @interface JXURLConnectionOperation : JXOperation
35 |
36 | /// @name Connection
37 |
38 | /**
39 | The request used to create the connection when the operation starts.
40 |
41 | Safe to access from any thread at any time.
42 | */
43 | @property (strong, readonly) NSMutableURLRequest *request;
44 |
45 | /**
46 | The connection response if one has been received, otherwise `nil`.
47 |
48 | Safe to access from any thread at any time.
49 | */
50 | @property (strong, readonly) NSURLResponse *response;
51 |
52 | /**
53 | The connection error if one has been received, otherwise `nil`.
54 |
55 | Safe to access from any thread at any time.
56 | */
57 | @property (strong, readonly) NSError *error;
58 |
59 | /**
60 | The stream to which downloaded bytes will be written.
61 |
62 | This can be set to any `NSOutputStream` or subclass thereof, providing that
63 | it is new and unopened. If this property is `nil` when the operation starts
64 | an `outputStreamToMemory` is created by default.
65 |
66 | Safe to access from any thread at any time.
67 |
68 | @warning Do not change this property after the operation has started.
69 | */
70 | @property (strong) NSOutputStream *outputStream;
71 |
72 | /// @name Progress
73 |
74 | /**
75 | The number of bytes downloaded.
76 |
77 | Safe to access from any thread at any time.
78 | */
79 | @property (assign, readonly) long long bytesDownloaded;
80 |
81 | /**
82 | The number of bytes uploaded.
83 |
84 | Safe to access from any thread at any time.
85 | */
86 | @property (assign, readonly) long long bytesUploaded;
87 |
88 | /// @name Initialization
89 |
90 | /**
91 | A shared thread that never exits. All connections and streams are scheduled
92 | on this thread's runloop.
93 |
94 | Safe to access from any thread at any time.
95 |
96 | @returns The shared thread used by all connections and streams.
97 | */
98 | + (NSThread *)sharedThread;
99 |
100 | /**
101 | Creates a new operation with a specified URL.
102 |
103 | @param url The URL to request.
104 | @returns An operation.
105 | */
106 | - (instancetype)initWithURL:(NSURL *)url;
107 |
108 | @end
109 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXURLConnectionOperation.m:
--------------------------------------------------------------------------------
1 | #import "JXURLConnectionOperation.h"
2 |
3 | @interface JXURLConnectionOperation ()
4 | @property (strong) NSURLConnection *connection;
5 | @property (strong) NSMutableURLRequest *request;
6 | @property (strong) NSURLResponse *response;
7 | @property (strong) NSError *error;
8 | @property (assign) long long bytesDownloaded;
9 | @property (assign) long long bytesUploaded;
10 | @end
11 |
12 | @implementation JXURLConnectionOperation
13 |
14 | #pragma mark - Initialization
15 |
16 | - (void)dealloc
17 | {
18 | [self stopConnection];
19 | }
20 |
21 | - (instancetype)init
22 | {
23 | if (self = [super init]) {
24 | self.connection = nil;
25 | self.request = nil;
26 | self.response = nil;
27 | self.error = nil;
28 | self.outputStream = nil;
29 |
30 | self.bytesDownloaded = 0LL;
31 | self.bytesUploaded = 0LL;
32 | }
33 | return self;
34 | }
35 |
36 | - (instancetype)initWithURL:(NSURL *)url
37 | {
38 | if (self = [self init]) {
39 | self.request = [[NSMutableURLRequest alloc] initWithURL:url];
40 | }
41 | return self;
42 | }
43 |
44 | #pragma mark - NSOperation
45 |
46 | - (void)main
47 | {
48 | if ([self isCancelled])
49 | return;
50 |
51 | [self startConnection];
52 | }
53 |
54 | - (void)willFinish
55 | {
56 | [super willFinish];
57 |
58 | [self stopConnection];
59 | }
60 |
61 | #pragma mark - Scheduling
62 |
63 | - (void)startConnection
64 | {
65 | if ([NSThread currentThread] != [[self class] sharedThread]) {
66 | [self performSelector:@selector(startConnection) onThread:[[self class] sharedThread] withObject:nil waitUntilDone:YES];
67 | return;
68 | }
69 |
70 | if ([self isCancelled])
71 | return;
72 |
73 | if (!self.outputStream)
74 | self.outputStream = [[NSOutputStream alloc] initToMemory];
75 |
76 | [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
77 |
78 | self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
79 | [self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
80 | [self.connection start];
81 | }
82 |
83 | - (void)stopConnection
84 | {
85 | if ([NSThread currentThread] != [[self class] sharedThread]) {
86 | [self performSelector:@selector(stopConnection) onThread:[[self class] sharedThread] withObject:nil waitUntilDone:YES];
87 | return;
88 | }
89 |
90 | [self.connection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
91 | [self.connection cancel];
92 |
93 | [self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
94 | [self.outputStream close];
95 | }
96 |
97 | + (NSThread *)sharedThread
98 | {
99 | static NSThread *thread = nil;
100 | static dispatch_once_t predicate;
101 |
102 | dispatch_once(&predicate, ^{
103 | thread = [[NSThread alloc] initWithTarget:self selector:@selector(runLoopForever) object:nil];
104 | [thread start];
105 | });
106 |
107 | return thread;
108 | }
109 |
110 | + (void)runLoopForever
111 | {
112 | [[NSThread currentThread] setName:@"JXHTTP"];
113 |
114 | while (YES) {
115 | @autoreleasepool {
116 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
117 | }
118 | }
119 | }
120 |
121 | #pragma mark -
122 |
123 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
124 | {
125 | if ([self isCancelled])
126 | return;
127 |
128 | self.error = error;
129 |
130 | [self finish];
131 | }
132 |
133 | #pragma mark -
134 |
135 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)urlResponse
136 | {
137 | if ([self isCancelled])
138 | return;
139 |
140 | self.response = urlResponse;
141 |
142 | [self.outputStream open];
143 | }
144 |
145 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
146 | {
147 | if ([self isCancelled])
148 | return;
149 |
150 | if ([self.outputStream hasSpaceAvailable]) {
151 | NSInteger bytesWritten = [self.outputStream write:[data bytes] maxLength:[data length]];
152 |
153 | if (bytesWritten != -1)
154 | self.bytesDownloaded += bytesWritten;
155 | }
156 | }
157 |
158 | - (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytes totalBytesWritten:(NSInteger)total totalBytesExpectedToWrite:(NSInteger)expected
159 | {
160 | if ([self isCancelled])
161 | return;
162 |
163 | self.bytesUploaded += bytes;
164 | }
165 |
166 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection
167 | {
168 | if ([self isCancelled])
169 | return;
170 |
171 | [self finish];
172 | }
173 |
174 | @end
175 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXURLEncoding.h:
--------------------------------------------------------------------------------
1 | /**
2 | `JXURLEncoding` is an abstract class providing methods for encoding strings according
3 | to [RFC 3986]( http://www.ietf.org/rfc/rfc3986.txt ) (aka "percent escaping").
4 | */
5 |
6 | @interface JXURLEncoding : NSObject
7 |
8 | /**
9 | Encodes a string according to RFC 3986.
10 |
11 | @param string A string to encode.
12 | @returns An encoded string.
13 | */
14 | + (NSString *)encodedString:(NSString *)string;
15 |
16 | /**
17 | Encodes a string according to RFC 3986, but with `+` replacing spaces instead of `%20`.
18 | Commonly used by web browsers to submit forms. When in doubt, use .
19 |
20 | @param string A string to encode.
21 | @returns An encoded string.
22 | */
23 | + (NSString *)formEncodedString:(NSString *)string;
24 |
25 | /**
26 | Encodes a dictionary according to RFC 3986, with keys sorted alphabetically and flattened
27 | into a query string. Dictionary values must be one of `NSString`, `NSArray`, or `NSDictionary`.
28 |
29 | ### Example ###
30 |
31 | NSDictionary *params = @{
32 | @"make": @"Ferrari",
33 | @"model": @"458 Italia",
34 | @"options": @[ @"heated seats", @"cup holders" ]
35 | };
36 |
37 | NSString *escaped = [JXURLEncoding encodedDictionary:params];
38 | // make=Ferrari&model=458%20Italia&options[0]=heated%20seats&options[1]=cup&20holders
39 |
40 | @param dictionary A dictionary to encode.
41 | @returns An encoded string.
42 | */
43 | + (NSString *)encodedDictionary:(NSDictionary *)dictionary;
44 |
45 | /**
46 | Encodes a dictionary according to RFC 3986, with keys sorted alphabetically and flattened
47 | into a query string. Dictionary values must be one of `NSString`, `NSArray`, or `NSDictionary`.
48 |
49 | Identical to but with `+` replacing spaces instead of `%20`.
50 |
51 | ### Example ###
52 |
53 | NSDictionary *params = @{
54 | @"make": @"Ferrari",
55 | @"model": @"458 Italia",
56 | @"options": @[ @"heated seats", @"cup holders" ]
57 | };
58 |
59 | NSString *escaped = [JXURLEncoding encodedDictionary:params];
60 | // make=Ferrari&model=458+Italia&options[0]=heated+seats&options[1]=cup+holders
61 |
62 | @param dictionary A dictionary to encode.
63 | @returns An encoded string.
64 | */
65 | + (NSString *)formEncodedDictionary:(NSDictionary *)dictionary;
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/JXHTTP/JXURLEncoding.m:
--------------------------------------------------------------------------------
1 | #import "JXURLEncoding.h"
2 |
3 | @implementation JXURLEncoding
4 |
5 | #pragma mark - NSString Encoding
6 |
7 | + (NSString *)encodedString:(NSString *)string
8 | {
9 | if (![string length])
10 | return @"";
11 |
12 | CFStringRef static const charsToLeave = CFSTR("-._~"); // RFC 3986 unreserved
13 | CFStringRef static const charsToEscape = CFSTR(":/?#[]@!$&'()*+,;="); // RFC 3986 reserved
14 | CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
15 | (__bridge CFStringRef)string,
16 | charsToLeave,
17 | charsToEscape,
18 | kCFStringEncodingUTF8);
19 | return (__bridge_transfer NSString *)escapedString;
20 | }
21 |
22 | + (NSString *)formEncodedString:(NSString *)string
23 | {
24 | if (![string length])
25 | return @"";
26 |
27 | return [[self encodedString:string] stringByReplacingOccurrencesOfString:@"%20" withString:@"+"];
28 | }
29 |
30 | #pragma mark - NSDictionary Encoding
31 |
32 | + (NSString *)encodedDictionary:(NSDictionary *)dictionary
33 | {
34 | if (![dictionary count])
35 | return @"";
36 |
37 | NSMutableArray *arguments = [[NSMutableArray alloc] initWithCapacity:[dictionary count]];
38 | NSArray *sortedKeys = [[dictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
39 |
40 | for (NSString *key in sortedKeys) {
41 | [self encodeObject:[dictionary objectForKey:key] withKey:key andSubKey:nil intoArray:arguments];
42 | }
43 |
44 | return [arguments componentsJoinedByString:@"&"];
45 | }
46 |
47 | + (NSString *)formEncodedDictionary:(NSDictionary *)dictionary
48 | {
49 | if (![dictionary count])
50 | return @"";
51 |
52 | return [[self encodedDictionary:dictionary] stringByReplacingOccurrencesOfString:@"%20" withString:@"+"];
53 | }
54 |
55 | #pragma mark - Private Methods
56 |
57 | + (void)encodeObject:(id)object withKey:(NSString *)key andSubKey:(NSString *)subKey intoArray:(NSMutableArray *)array
58 | {
59 | if (!object || ![key length])
60 | return;
61 |
62 | NSString *objectKey = nil;
63 |
64 | if (subKey) {
65 | objectKey = [[NSString alloc] initWithFormat:@"%@[%@]", [self encodedString:key], [self encodedString:subKey]];
66 | } else {
67 | objectKey = [self encodedString:key];
68 | }
69 |
70 | if ([object isKindOfClass:[NSDictionary class]]) {
71 | NSArray *sortedKeys = [[object allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
72 | for (NSString *insideKey in sortedKeys) {
73 | [self encodeObject:[object objectForKey:insideKey] withKey:objectKey andSubKey:insideKey intoArray:array];
74 | }
75 | } else if ([object isKindOfClass:[NSArray class]]) {
76 | for (NSString *arrayObject in (NSArray *)object) {
77 | NSString *arrayKey = [[NSString alloc] initWithFormat:@"%@[]", objectKey];
78 | [self encodeObject:arrayObject withKey:arrayKey andSubKey:nil intoArray:array];
79 | }
80 | } else if ([object isKindOfClass:[NSNumber class]]) {
81 | [array addObject:[[NSString alloc] initWithFormat:@"%@=%@", objectKey, [object stringValue]]];
82 | } else {
83 | NSString *encodedString = [self encodedString:object];
84 | [array addObject:[[NSString alloc] initWithFormat:@"%@=%@", objectKey, encodedString]];
85 | }
86 | }
87 |
88 | @end
89 |
--------------------------------------------------------------------------------
/Pods/JXHTTP/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Justin Ouellette
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
--------------------------------------------------------------------------------
/Pods/JXHTTP/README.md:
--------------------------------------------------------------------------------
1 | # JXHTTP #
2 |
3 | JXHTTP is a networking library for iOS and OS X. It leverages operation queues and GCD to provide a powerful wrapper for Cocoa's built-in `NSURLConnection` object, adding many useful features like block response objects and progress tracking across multiple requests. It strives to be as lightweight and readable as possible, making it easy to use or customize for advanced behavior.
4 |
5 | To get started, simply [download the latest tag](https://github.com/jstn/JXHTTP/tags) and drop the `JXHTTP` folder into your Xcode project. There are zero external dependencies or special compiler flags, just `#import "JXHTTP.h"` somewhere convenient. A complete docset is included for use in Xcode or [Dash](http://kapeli.com/dash/), and available online at [jxhttp.com](http://jxhttp.com/docs/html/). JXHTTP is also available as a [CocoaPod](http://cocoapods.org/?q=name%3AJXHTTP).
6 |
7 | JXHTTP requires iOS 5.0 or OS X 10.7 or newer.
8 |
9 | ## Advantages ##
10 |
11 | [JXHTTPOperation](JXHTTP/JXHTTPOperation.h) offers a number of advantages over using vanilla `NSURLConnection` without an operation wrapper:
12 |
13 | - requests can be easily grouped, prioritized, cancelled, and executed concurrently
14 | - data can be streamed to and from disk for excellent memory efficiency
15 | - requests can optionally continue executing when the app is sent to the background
16 | - progress is easily tracked via delegate methods, response blocks, KVO, or all three
17 | - requests run entirely on background threads, away from the main thread and UI
18 | - particular attention has been paid to thread safety and is well-documented throughout
19 |
20 | JXHTTP is production-ready and currently powers the [Tumblr iOS SDK](http://tumblr.com/mobile); thousands of successful requests were performed while you read this paragraph!
21 |
22 | ## Examples ##
23 |
24 | See the included [example project](example/) for a real-world use case in iOS.
25 |
26 | ### Asynchronous ###
27 |
28 | ```objective-c
29 | JXHTTPOperation *op = [JXHTTPOperation withURLString:@"https://encrypted.google.com/"];
30 | op.didFinishLoadingBlock = ^(JXHTTPOperation *op) {
31 | NSLog(@"%@", op.responseString);
32 | };
33 |
34 | [[JXHTTPOperationQueue sharedQueue] addOperation:op];
35 | ```
36 |
37 | ### Synchronous ###
38 |
39 | ```objective-c
40 | JXHTTPOperation *op = [JXHTTPOperation withURLString:@"https://encrypted.google.com/"];
41 | [op startAndWaitUntilFinished];
42 |
43 | NSLog(@"%@", op.responseString);
44 | ```
45 |
46 | ### Complex ###
47 |
48 | ```objective-c
49 | NSURL *postURL = [NSURL URLWithString:@"https://web.site/api/POST"];
50 | NSDictionary *postParams = @{ @"make": @"Ferrari", @"model": @"458 Italia" };
51 |
52 | JXHTTPOperation *op = [[JXHTTPOperation alloc] initWithURL:postURL];
53 | op.requestBody = [[JXHTTPFormEncodedBody alloc] initWithDictionary:postParams];
54 | op.requestCachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;
55 | op.responseDataFilePath = @"/tmp/downloaded_data";
56 | op.trustedHosts = @[ postURL.host ];
57 | op.performsBlocksOnMainQueue = YES;
58 |
59 | op.didSendDataBlock = ^(JXHTTPOperation *op) {
60 | NSLog(@"%lld bytes uploaded so far", op.bytesUploaded);
61 | };
62 |
63 | [[JXHTTPOperationQueue sharedQueue] addOperation:op];
64 | ```
65 |
66 | ## Contact ##
67 |
68 | JXHTTP was created by [Justin Ouellette](http://justinouellette.com/).
69 |
70 | Email [jstn@jxhttp.com](mailto:jstn@jxhttp.com) with questions.
--------------------------------------------------------------------------------
/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - JXHTTP (1.0.0)
3 | - TMTumblrSDK (1.0.8):
4 | - TMTumblrSDK/Activity
5 | - TMTumblrSDK/APIClient
6 | - TMTumblrSDK/AppClient
7 | - TMTumblrSDK/Core
8 | - TMTumblrSDK/Activity (1.0.8)
9 | - TMTumblrSDK/APIClient (1.0.8):
10 | - JXHTTP (= 1.0.0)
11 | - TMTumblrSDK/APIClient/Authentication
12 | - TMTumblrSDK/APIClient/Authentication (1.0.8):
13 | - JXHTTP (= 1.0.0)
14 | - TMTumblrSDK/Core
15 | - TMTumblrSDK/AppClient (1.0.8):
16 | - TMTumblrSDK/Core
17 | - TMTumblrSDK/Core (1.0.8)
18 |
19 | DEPENDENCIES:
20 | - TMTumblrSDK
21 |
22 | SPEC CHECKSUMS:
23 | JXHTTP: dd1fe9c6fa21e7b2be9724ef2be16c66aafc44b4
24 | TMTumblrSDK: b9fada23e88b42ade2b492a6db95bfb1dff6304b
25 |
26 | COCOAPODS: 0.33.1
27 |
--------------------------------------------------------------------------------
/Pods/Pods-JXHTTP-Private.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods-JXHTTP.xcconfig"
2 | GCC_PREPROCESSOR_DEFINITIONS = COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/BuildHeaders" "${PODS_ROOT}/BuildHeaders/JXHTTP" "${PODS_ROOT}/Headers" "${PODS_ROOT}/Headers/JXHTTP" "${PODS_ROOT}/Headers/TMTumblrSDK"
4 | OTHER_LDFLAGS = -ObjC ${PODS_JXHTTP_OTHER_LDFLAGS}
5 | PODS_ROOT = ${SRCROOT}
--------------------------------------------------------------------------------
/Pods/Pods-JXHTTP-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_JXHTTP : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_JXHTTP
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Pods-JXHTTP-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 | #import "Pods-environment.h"
6 |
--------------------------------------------------------------------------------
/Pods/Pods-JXHTTP.xcconfig:
--------------------------------------------------------------------------------
1 | PODS_JXHTTP_OTHER_LDFLAGS = -framework Foundation -weak_framework UIKit
--------------------------------------------------------------------------------
/Pods/Pods-TMTumblrSDK-Private.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods-TMTumblrSDK.xcconfig"
2 | GCC_PREPROCESSOR_DEFINITIONS = COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/BuildHeaders" "${PODS_ROOT}/BuildHeaders/TMTumblrSDK" "${PODS_ROOT}/Headers" "${PODS_ROOT}/Headers/JXHTTP" "${PODS_ROOT}/Headers/TMTumblrSDK"
4 | OTHER_LDFLAGS = -ObjC ${PODS_TMTUMBLRSDK_OTHER_LDFLAGS}
5 | PODS_ROOT = ${SRCROOT}
--------------------------------------------------------------------------------
/Pods/Pods-TMTumblrSDK-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_TMTumblrSDK : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_TMTumblrSDK
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Pods-TMTumblrSDK-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 | #import "Pods-environment.h"
6 |
--------------------------------------------------------------------------------
/Pods/Pods-TMTumblrSDK.xcconfig:
--------------------------------------------------------------------------------
1 | PODS_TMTUMBLRSDK_OTHER_LDFLAGS = -framework Foundation -weak_framework UIKit
--------------------------------------------------------------------------------
/Pods/Pods-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods : NSObject
3 | @end
4 | @implementation PodsDummy_Pods
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Pods-environment.h:
--------------------------------------------------------------------------------
1 |
2 | // To check if a library is compiled with CocoaPods you
3 | // can use the `COCOAPODS` macro definition which is
4 | // defined in the xcconfigs so it is available in
5 | // headers also when they are imported in the client
6 | // project.
7 |
8 |
9 | // JXHTTP
10 | #define COCOAPODS_POD_AVAILABLE_JXHTTP
11 | #define COCOAPODS_VERSION_MAJOR_JXHTTP 1
12 | #define COCOAPODS_VERSION_MINOR_JXHTTP 0
13 | #define COCOAPODS_VERSION_PATCH_JXHTTP 0
14 |
15 | // TMTumblrSDK
16 | #define COCOAPODS_POD_AVAILABLE_TMTumblrSDK
17 | #define COCOAPODS_VERSION_MAJOR_TMTumblrSDK 1
18 | #define COCOAPODS_VERSION_MINOR_TMTumblrSDK 0
19 | #define COCOAPODS_VERSION_PATCH_TMTumblrSDK 8
20 |
21 | // TMTumblrSDK/APIClient
22 | #define COCOAPODS_POD_AVAILABLE_TMTumblrSDK_APIClient
23 | #define COCOAPODS_VERSION_MAJOR_TMTumblrSDK_APIClient 1
24 | #define COCOAPODS_VERSION_MINOR_TMTumblrSDK_APIClient 0
25 | #define COCOAPODS_VERSION_PATCH_TMTumblrSDK_APIClient 8
26 |
27 | // TMTumblrSDK/APIClient/Authentication
28 | #define COCOAPODS_POD_AVAILABLE_TMTumblrSDK_APIClient_Authentication
29 | #define COCOAPODS_VERSION_MAJOR_TMTumblrSDK_APIClient_Authentication 1
30 | #define COCOAPODS_VERSION_MINOR_TMTumblrSDK_APIClient_Authentication 0
31 | #define COCOAPODS_VERSION_PATCH_TMTumblrSDK_APIClient_Authentication 8
32 |
33 | // TMTumblrSDK/Activity
34 | #define COCOAPODS_POD_AVAILABLE_TMTumblrSDK_Activity
35 | #define COCOAPODS_VERSION_MAJOR_TMTumblrSDK_Activity 1
36 | #define COCOAPODS_VERSION_MINOR_TMTumblrSDK_Activity 0
37 | #define COCOAPODS_VERSION_PATCH_TMTumblrSDK_Activity 8
38 |
39 | // TMTumblrSDK/AppClient
40 | #define COCOAPODS_POD_AVAILABLE_TMTumblrSDK_AppClient
41 | #define COCOAPODS_VERSION_MAJOR_TMTumblrSDK_AppClient 1
42 | #define COCOAPODS_VERSION_MINOR_TMTumblrSDK_AppClient 0
43 | #define COCOAPODS_VERSION_PATCH_TMTumblrSDK_AppClient 8
44 |
45 | // TMTumblrSDK/Core
46 | #define COCOAPODS_POD_AVAILABLE_TMTumblrSDK_Core
47 | #define COCOAPODS_VERSION_MAJOR_TMTumblrSDK_Core 1
48 | #define COCOAPODS_VERSION_MINOR_TMTumblrSDK_Core 0
49 | #define COCOAPODS_VERSION_PATCH_TMTumblrSDK_Core 8
50 |
51 |
--------------------------------------------------------------------------------
/Pods/Pods-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
5 | > "$RESOURCES_TO_COPY"
6 |
7 | install_resource()
8 | {
9 | case $1 in
10 | *.storyboard)
11 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
12 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
13 | ;;
14 | *.xib)
15 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}"
16 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}"
17 | ;;
18 | *.framework)
19 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
20 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
21 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
22 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
23 | ;;
24 | *.xcdatamodel)
25 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\""
26 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom"
27 | ;;
28 | *.xcdatamodeld)
29 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\""
30 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd"
31 | ;;
32 | *.xcassets)
33 | ;;
34 | /*)
35 | echo "$1"
36 | echo "$1" >> "$RESOURCES_TO_COPY"
37 | ;;
38 | *)
39 | echo "${PODS_ROOT}/$1"
40 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY"
41 | ;;
42 | esac
43 | }
44 | install_resource "TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr.png"
45 | install_resource "TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr@2x.png"
46 | install_resource "TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr@2x~ipad.png"
47 | install_resource "TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr~ipad.png"
48 | install_resource "TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr~ipad@2x.png"
49 |
50 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
51 | if [[ "${ACTION}" == "install" ]]; then
52 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
53 | fi
54 | rm -f "$RESOURCES_TO_COPY"
55 |
56 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ `xcrun --find actool` ] && [ `find . -name '*.xcassets' | wc -l` -ne 0 ]
57 | then
58 | case "${TARGETED_DEVICE_FAMILY}" in
59 | 1,2)
60 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
61 | ;;
62 | 1)
63 | TARGET_DEVICE_ARGS="--target-device iphone"
64 | ;;
65 | 2)
66 | TARGET_DEVICE_ARGS="--target-device ipad"
67 | ;;
68 | *)
69 | TARGET_DEVICE_ARGS="--target-device mac"
70 | ;;
71 | esac
72 | find "${PWD}" -name "*.xcassets" -print0 | xargs -0 actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
73 | fi
74 |
--------------------------------------------------------------------------------
/Pods/Pods.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers" "${PODS_ROOT}/Headers/JXHTTP" "${PODS_ROOT}/Headers/TMTumblrSDK"
3 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers" -isystem "${PODS_ROOT}/Headers/JXHTTP" -isystem "${PODS_ROOT}/Headers/TMTumblrSDK"
4 | OTHER_LDFLAGS = -ObjC -framework Foundation -weak_framework UIKit
5 | PODS_ROOT = ${SRCROOT}/Pods
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/bryan.xcuserdatad/xcschemes/Pods-JXHTTP.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/bryan.xcuserdatad/xcschemes/Pods-TMTumblrSDK.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/bryan.xcuserdatad/xcschemes/Pods.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
42 |
43 |
44 |
45 |
51 |
52 |
54 |
55 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/bryan.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Pods-JXHTTP.xcscheme
8 |
9 | isShown
10 |
11 |
12 | Pods-TMTumblrSDK.xcscheme
13 |
14 | isShown
15 |
16 |
17 | Pods.xcscheme
18 |
19 | isShown
20 |
21 |
22 |
23 | SuppressBuildableAutocreation
24 |
25 | 575669C318D1479286D118E3
26 |
27 | primary
28 |
29 |
30 | 59E5373C93D1430C9C69ECCE
31 |
32 | primary
33 |
34 |
35 | E8946277823C474AB54B797E
36 |
37 | primary
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/README.md:
--------------------------------------------------------------------------------
1 | # Tumblr SDK for iOS
2 |
3 | An unopinionated and flexible library for easily integrating Tumblr data into
4 | your iOS or OS X application. The library uses ARC and requires at least iOS 5 or
5 | OS X 10.7.
6 |
7 | ``` objectivec
8 | [[TMAPIClient sharedInstance] blogInfo:@"bryan" success:^ (id result, NSError *error) {
9 | if (error) {
10 | NSLog(@"Bummer, dude: %@", error);
11 | return;
12 | }
13 |
14 | NSLog(@"Blog description: %@", result[@"description"]);
15 | }];
16 | ```
17 |
18 | If you have any feature requests, please let us know by creating an issue or
19 | submitting a pull request. Please use the Tumblr API [responsibly](http://www.tumblr.com/docs/en/api_agreement).
20 |
21 | [](https://travis-ci.org/tumblr/TMTumblrSDK)
22 |
23 | ## Table of Contents
24 |
25 | * [Getting started](#getting-started)
26 | * [CocoaPods](#cocoapods)
27 | * [Documentation](#documentation)
28 | * [Authentication](#authentication)
29 | * [OAuth](#oauth)
30 | * [xAuth](#xauth)
31 | * [API client](#api-client)
32 | * [Inter-app communication](#inter-app-communication)
33 | * [App client](#app-client)
34 | * [URL schemes](#url-schemes)
35 | * [UIDocumentInteractionController](#uidocumentinteractioncontroller)
36 | * [UIActivityViewController](#uiactivityviewcontroller)
37 | * [Example](#example)
38 | * [Contact](#contact)
39 | * [License](#license)
40 |
41 | ## Getting started
42 |
43 | ### CocoaPods
44 |
45 | [CocoaPods](http://cocoapods.org) is the recommended way to add the Tumblr
46 | SDK to your project. *Using CocoaPods means you don't need to worry about
47 | cloning or adding this repository as a git submodule.* CocoaPods is a package
48 | manager like `gem` (Ruby) and `npm` (Node.js), but for Objective-C projects.
49 |
50 | Module authors create "pods" which are versioned and stored in a central
51 | repository. App developers create "podfiles" to specify their apps'
52 | dependencies and use the CocoaPods command line tool to:
53 |
54 | * Fetch the dependencies specified in their podfile
55 | * Recursively fetch all subdependencies
56 | * Create an Xcode workspace that includes the pods, links any necessary libraries,
57 | configures header search paths, enables ARC where appropriate, and more
58 |
59 | If you're new to CocoaPods, the website contains lots of helpful [documentation](http://docs.cocoapods.org).
60 |
61 | To install the Tumblr SDK you can simply create a
62 | [podfile](https://github.com/CocoaPods/CocoaPods/wiki/A-Podfile)
63 | in your application's root directory that looks as follows:
64 |
65 | ``` ruby
66 | platform :ios, '5.0'
67 |
68 | pod 'TMTumblrSDK'
69 | ```
70 |
71 | After running `pod install`, you'll have an Xcode workspace that includes not
72 | only your application but also the Tumblr SDK and its dependencies. That's really
73 | all there is to it.
74 |
75 | You will get the latest version of the SDK by referring to it simply by name
76 | (`TMTumblrSDK`). [This guide](http://docs.cocoapods.org/guides/dependency_versioning.html)
77 | explains how explicit dependency versions can instead be specified.
78 |
79 | This SDK is really comprised of numerous "sub-pods." If you'd rather not import
80 | everything, feel free to mix and match as you see fit:
81 |
82 | * `TMTumblrSDK/APIClient`
83 | * `TMTumblrSDK/APIClient/Authentication`
84 | * `TMTumblrSDK/AppClient`
85 | * `TMTumblrSDK/Activity`
86 |
87 |
88 | Each component is described in more detail throughout this README.
89 |
90 | ### Documentation
91 |
92 | Appledoc for the SDK can be found [here](http://cocoadocs.org/docsets/TMTumblrSDK).
93 | If you install the Tumblr SDK using CocoaPods, the docset is automatically added
94 | to Xcode for you.
95 |
96 | ## Authentication
97 |
98 | Import `TMAPIClient.h`. Configure the `[TMAPIClient sharedInstance]` singleton
99 | with your app’s Tumblr consumer key and secret:
100 |
101 | ``` objectivec
102 | [TMAPIClient sharedInstance].OAuthConsumerKey = @"ADISJdadsoj2dj38dj29dj38jd9238jdk92djasdjASDaoijsd";
103 | [TMAPIClient sharedInstance].OAuthConsumerSecret = @"MGI39kdasdoka3240989ASFjoiajsfomdasd39129ASDAPDOJa";
104 | ```
105 |
106 | If you don't already have a consumer key/secret you can
107 | register [here](http://www.tumblr.com/oauth/apps).
108 |
109 | The authentication methods detailed below will provide the API client with a token and token secret. The
110 | SDK does *not* currently persist these values; you are responsible for storing them and setting them on
111 | the API client on subsequent app launches, before making any API requests. This may change in a future
112 | release.
113 |
114 | ### OAuth
115 | In your app’s `Info.plist`, specify a custom URL scheme that the browser can
116 | use to return to your application once the user has permitted or denied
117 | access to Tumblr:
118 |
119 | ``` xml
120 | CFBundleURLTypes
121 |
122 |
123 | CFBundleURLSchemes
124 |
125 | myapp
126 |
127 |
128 |
129 | ```
130 |
131 | In your app delegate, allow the `TMAPIClient` singleton to handle incoming URL
132 | requests. On iOS this looks like:
133 |
134 | ``` objectivec
135 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication
136 | annotation:(id)annotation {
137 | return [[TMAPIClient sharedInstance] handleOpenURL:url];
138 | }
139 | ```
140 |
141 | And on OS X:
142 |
143 | ``` objectivec
144 | - (void)applicationWillFinishLaunching:(NSNotification *)notification {
145 | NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
146 | [appleEventManager setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:)
147 | forEventClass:kInternetEventClass andEventID:kAEGetURL];
148 | }
149 |
150 | - (void)handleURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent {
151 | NSString *calledURL = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
152 |
153 | [[TMAPIClient sharedInstance] handleOpenURL:[NSURL URLWithString:calledURL]];
154 | }
155 | ```
156 |
157 | Initiate the three-legged OAuth flow, by specifying the URL scheme that your
158 | app will respond to:
159 |
160 | ``` objectivec
161 | [[TMAPIClient sharedInstance] authenticate:@"myapp" callback:^(NSError *error) {
162 | // You are now authenticated (if !error)
163 | }];
164 | ```
165 |
166 | ### xAuth
167 |
168 | Please note that xAuth access
169 | [must be specifically requested](http://www.tumblr.com/oauth/apps)
170 | for your application.
171 |
172 | Use the `TMAPIClient` singleton to retrieve an OAuth token and secret given a
173 | user’s email address and password:
174 |
175 | ``` objectivec
176 | [[TMAPIClient sharedInstance] xAuth:@"foo@foo.bar" password:@"12345" callback:^(NSError *error) {
177 | // You are now authenticated (if !error)
178 | }];
179 | ```
180 |
181 | If you're only interested in authentication, the
182 | `TMTumblrSDK/APIClient/Authentication` sub-pod can be installed by itself.
183 |
184 | ## API client
185 |
186 | Please view the [API documentation](http://www.tumblr.com/docs/en/api/v2) for
187 | full usage instructions.
188 |
189 | There are two ways of retrieving data from the API:
190 |
191 | ``` objectivec
192 | // `void` methods for immediate requests, preferable when the caller does not need a reference to an actual request object:
193 |
194 | [[TMAPIClient sharedInstance] userInfo:^(id result, NSError *error) {
195 | if (!error)
196 | NSLog(@"Got some user info");
197 | }];
198 |
199 | // Methods that return configured, signed `JXHTTPOperation` instances and require the client to explicitly send the request separately.
200 |
201 | JXHTTPOperation *likesRequest = [[TMAPIClient sharedInstance] likesRequest:@"bryan" parameters:nil];
202 | ```
203 |
204 | The API client is built on top of the
205 | [JXHTTP](https://github.com/jstn/JXHTTP) networking library. If you're only
206 | interested in the API client, the `TMTumblrSDK/APIClient` sub-pod can be
207 | installed by itself.
208 |
209 | ## Inter-app communication
210 |
211 | ### App client
212 |
213 | The `TMTumblrAppClient` class provides a simple interface for interacting with
214 | [Tumblr for iOS](https://itunes.apple.com/us/app/tumblr/id305343404?mt=8) if the
215 | user has it installed. Only a few basic endpoints are supported for now but more
216 | will be added in the near future:
217 |
218 | ``` objectivec
219 | if (![TMTumblrAppClient isTumblrInstalled]) {
220 | [TMTumblrAppClient viewInAppStore];
221 | }
222 |
223 | [TMTumblrAppClient viewDashboard];
224 |
225 | [TMTumblrAppClient viewTag:@"gif"];
226 |
227 | [TMTumblrAppClient viewBlog:@"bryan"];
228 |
229 | [TMTumblrAppClient viewPost:@"43724939726" blogName:@"bryan"];
230 | ```
231 |
232 | If you're only interested in the app client,
233 | the `TMTumblrSDK/AppClient` sub-pod can be installed by itself.
234 |
235 | #### URL schemes
236 |
237 | Tumblr for iOS exposes actions using the [x-callback-url](http://x-callback-url.com/)
238 | specification. The `TMTumblrAppClient` class merely provides a convenient
239 | interface on top of the following URLs:
240 |
241 | ```
242 | tumblr://x-callback-url/dashboard
243 | tumblr://x-callback-url/tag?tag=gif
244 | tumblr://x-callback-url/blog?blogName=bryan
245 | tumblr://x-callback-url/blog?blogName=bryan&postID=43724939726
246 |
247 | // The post URLs below also support `x-success` and `x-cancel` callback parameters
248 |
249 | tumblr://x-callback-url/text?title=Title&body=Body&tags=gif&tags=lol
250 | tumblr://x-callback-url/quote?quote=Quote&source=Source
251 | tumblr://x-callback-url/link?title=Bryan&url=bryan.io&description=Website
252 | tumblr://x-callback-url/chat?title=Title&body=Body&tags=gif&tags=lol
253 | ```
254 |
255 | If you don't want to use this SDK and would rather hit these URLs directly, please go
256 | right ahead.
257 |
258 | ### UIDocumentInteractionController
259 |
260 | Photos and videos can be passed to Tumblr for iOS using Apple's
261 | standard [UIDocumentInteractionController](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIDocumentInteractionController_class/Reference/Reference.html).
262 |
263 | To include a caption, set the `annotation` property on the document
264 | interaction controller to an `NSDictionary` containing a `TumblrCaption`
265 | key, mapped to your caption (an `NSString`). To include tags, add a
266 | `TumblrTags` key to the dictionary, mapped an an `NSArray` of `NSStrings`.
267 |
268 | If you want *only* the Tumblr app to show up in a document interaction controller,
269 | you can specify the file extension `tumblrphoto` and custom UTI `com.tumblr.photo`.
270 |
271 | ### UIActivityViewController
272 |
273 | The SDK includes a [UIActivity subclass](https://github.com/tumblr/TMTumblrSDK/blob/master/TMTumblrSDK/Activity/TMTumblrActivity.h)
274 | for including Tumblr in a standard `UIActivityViewController`. It currently
275 | provides only the activity icon and title, but you can hook it up however you
276 | see fit and we may provide a more integrated solution in the future.
277 |
278 | If you're only interested in this UIActivity subclass,
279 | the `TMTumblrSDK/Activity` sub-pod can be installed by itself.
280 |
281 | ### Example
282 |
283 | The repository includes a [sample application](https://github.com/tumblr/TMTumblrSDK/tree/master/Examples/AppClientExample)
284 | which shows all of the inter-app hooks in action.
285 |
286 | 
287 |
288 | ## Dependencies
289 |
290 | * [JXHTTP](https://github.com/jstn/JXHTTP)
291 |
292 | ## Contact
293 |
294 | * [Bryan Irace](bryan@tumblr.com)
295 | * [Tumblr API discussion group](https://groups.google.com/group/tumblr-api/)
296 |
297 | ## License
298 |
299 | Copyright 2012 Tumblr, Inc.
300 |
301 | Licensed under the Apache License, Version 2.0 (the “License”); you may not use
302 | this file except in compliance with the License. You may obtain a copy of the
303 | License at [apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0).
304 |
305 | > Unless required by applicable law or agreed to in writing, software
306 | > distributed under the License is distributed on an “AS IS” BASIS, WITHOUT
307 | > WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
308 | > License for the specific language governing permissions and limitations under
309 | > the License.
310 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Activity/TMTumblrActivity.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMTumblrActivity.h
3 | // TumblrAppClient
4 | //
5 | // Created by Bryan Irace on 3/19/13.
6 | // Copyright (c) 2013 Tumblr. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | `TMTumblrActivity` provides the bare minimum `UIActivity` subclass necessary to start sharing to Tumblr: just the name
13 | and icon.
14 |
15 | For now this is essentially a blank canvas to be used in conjunction with either `TMAPIClient` or `TMTumblrAppClient`.
16 | This should be subclassed in accordance with the `UIActivity` documentation to actually perform an action based on
17 | provided activity items. In the future we may provide a more integrated solution.
18 | */
19 | @interface TMTumblrActivity : UIActivity
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Activity/TMTumblrActivity.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMTumblrActivity.m
3 | // TumblrAppClient
4 | //
5 | // Created by Bryan Irace on 3/19/13.
6 | // Copyright (c) 2013 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMTumblrActivity.h"
10 |
11 | @implementation TMTumblrActivity
12 |
13 | - (BOOL)canPerformWithActivityItems:(NSArray *)activityItems {
14 | return YES;
15 | }
16 |
17 | - (NSString *)activityType {
18 | return NSStringFromClass([self class]);
19 | }
20 |
21 | - (NSString *)activityTitle {
22 | return @"Tumblr";
23 | }
24 |
25 | - (UIImage *)activityImage {
26 | return [UIImage imageNamed:@"UIActivityTumblr"];
27 | }
28 |
29 | #ifdef __IPHONE_7_0
30 | + (UIActivityCategory)activityCategory {
31 | return UIActivityCategoryShare;
32 | }
33 | #endif
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TumblrArchive/CoreDataExample/fdcba11b8581ccafeceaa7423967f332c985ffb5/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr.png
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TumblrArchive/CoreDataExample/fdcba11b8581ccafeceaa7423967f332c985ffb5/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr@2x.png
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr@2x~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TumblrArchive/CoreDataExample/fdcba11b8581ccafeceaa7423967f332c985ffb5/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr@2x~ipad.png
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr~ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TumblrArchive/CoreDataExample/fdcba11b8581ccafeceaa7423967f332c985ffb5/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr~ipad.png
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr~ipad@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TumblrArchive/CoreDataExample/fdcba11b8581ccafeceaa7423967f332c985ffb5/Pods/TMTumblrSDK/TMTumblrSDK/Activity/UIActivityTumblr~ipad@2x.png
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/AppClient/TMTumblrAppClient.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMTumblrAppClient.h
3 | // TumblrAppClient
4 | //
5 | // Created by Bryan Irace on 11/24/12.
6 | // Copyright (c) 2012 Tumblr. All rights reserved.
7 | //
8 |
9 | /**
10 | Convenience wrapper around the URLs that [Tumblr for iOS](https://itunes.apple.com/us/app/tumblr/id305343404) knows how
11 | to open.
12 | */
13 | @interface TMTumblrAppClient : NSObject
14 |
15 | /// Check if the Tumblr app is installed
16 | + (BOOL)isTumblrInstalled;
17 |
18 | /// Open Tumblr for iOS in the App Store
19 | + (void)viewInAppStore;
20 |
21 | /// View the authenticated user's dashboard
22 | + (void)viewDashboard;
23 |
24 | /// View a tag
25 | + (void)viewTag:(NSString *)tag;
26 |
27 | /// View a blog
28 | + (void)viewBlog:(NSString *)blogName;
29 |
30 | /// View a blog's post
31 | + (void)viewPost:(NSString *)postID blogName:(NSString *)blogName;
32 |
33 | /// Create a text post with a title, body, and tags
34 | + (void)createTextPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags;
35 |
36 | /// Create a text post with a title, body, tags, and success/cancel URLs
37 | + (void)createTextPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags success:(NSURL *)successURL
38 | cancel:(NSURL *)cancelURL;
39 |
40 | /// Create a quote post with a quote, source, and tags
41 | + (void)createQuotePost:(NSString *)quote source:(NSString *)source tags:(NSArray *)tags;
42 |
43 | /// Create a quote post with a quote, source, tags, and success/cancel URLs
44 | + (void)createQuotePost:(NSString *)quote source:(NSString *)source tags:(NSArray *)tags success:(NSURL *)successURL
45 | cancel:(NSURL *)cancelURL;
46 |
47 | /// Create a link post with a title, URL, description, and tags
48 | + (void)createLinkPost:(NSString *)title URLString:(NSString *)URLString description:(NSString *)description
49 | tags:(NSArray *)tags;
50 |
51 | /// Create a link post with a title, URL, description, tags, and success/cancel URLs
52 | + (void)createLinkPost:(NSString *)title URLString:(NSString *)URLString description:(NSString *)description
53 | tags:(NSArray *)tags success:(NSURL *)successURL cancel:(NSURL *)cancelURL;
54 |
55 | /// Create a chat post with a title, body, and tags
56 | + (void)createChatPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags;
57 |
58 | /// Create a chat post with a title, body, tags, and success/cancel URLs
59 | + (void)createChatPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags success:(NSURL *)successURL
60 | cancel:(NSURL *)cancelURL;
61 |
62 | @end
63 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/AppClient/TMTumblrAppClient.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMTumblrAppClient.m
3 | // TumblrAppClient
4 | //
5 | // Created by Bryan Irace on 11/24/12.
6 | // Copyright (c) 2012 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMTumblrAppClient.h"
10 |
11 | #import
12 | #import "TMSDKFunctions.h"
13 |
14 | @implementation TMTumblrAppClient
15 |
16 | + (BOOL)isTumblrInstalled {
17 | return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tumblr://"]];
18 | }
19 |
20 | + (void)viewInAppStore {
21 | [[UIApplication sharedApplication] openURL:
22 | [NSURL URLWithString:@"itms-apps://itunes.apple.com/us/app/tumblr/id305343404"]];
23 | }
24 |
25 | + (void)viewDashboard {
26 | [self performAction:@"dashboard" parameters:nil];
27 | }
28 |
29 | + (void)viewTag:(NSString *)tag {
30 | if (tag) {
31 | [self performAction:@"tag" parameters:@{ @"tag" : tag }];
32 | }
33 | }
34 |
35 | + (void)viewBlog:(NSString *)blogName {
36 | if (blogName) {
37 | [self performAction:@"blog" parameters:@{ @"blogName" : blogName }];
38 | }
39 | }
40 |
41 | + (void)viewPost:(NSString *)postID blogName:(NSString *)blogName {
42 | if (blogName) {
43 | NSMutableDictionary *params = [[NSMutableDictionary alloc] initWithDictionary:@{ @"blogName" : blogName }];
44 | [params setValue:postID forKey:@"postID"];
45 |
46 | [self performAction:@"blog" parameters:params];
47 | }
48 | }
49 |
50 | + (void)createTextPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags {
51 | [self createTextPost:title body:body tags:tags success:nil cancel:nil];
52 | }
53 |
54 | + (void)createTextPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags success:(NSURL *)successURL
55 | cancel:(NSURL *)cancelURL {
56 | NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
57 | [params setValue:title forKey:@"title"];
58 | [params setValue:body forKey:@"body"];
59 | [params setValue:tags forKey:@"tags"];
60 |
61 | [self performAction:@"text" parameters:params success:successURL cancel:cancelURL];
62 | }
63 |
64 | + (void)createQuotePost:(NSString *)quote source:(NSString *)source tags:(NSArray *)tags {
65 | [self createQuotePost:quote source:source tags:tags success:nil cancel:nil];
66 | }
67 |
68 | + (void)createQuotePost:(NSString *)quote source:(NSString *)source tags:(NSArray *)tags success:(NSURL *)successURL
69 | cancel:(NSURL *)cancelURL {
70 | NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
71 | [params setValue:quote forKey:@"quote"];
72 | [params setValue:source forKey:@"source"];
73 | [params setValue:tags forKey:@"tags"];
74 |
75 | [self performAction:@"quote" parameters:params success:successURL cancel:cancelURL];
76 | }
77 |
78 | + (void)createLinkPost:(NSString *)title URLString:(NSString *)URLString description:(NSString *)description
79 | tags:(NSArray *)tags {
80 | [self createLinkPost:title URLString:URLString description:description tags:tags success:nil cancel:nil];
81 | }
82 |
83 | + (void)createLinkPost:(NSString *)title URLString:(NSString *)URLString description:(NSString *)description
84 | tags:(NSArray *)tags success:(NSURL *)successURL cancel:(NSURL *)cancelURL {
85 | NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
86 | [params setValue:title forKey:@"title"];
87 | [params setValue:URLString forKey:@"url"];
88 | [params setValue:description forKey:@"description"];
89 | [params setValue:tags forKey:@"tags"];
90 |
91 | [self performAction:@"link" parameters:params success:successURL cancel:cancelURL];
92 | }
93 |
94 | + (void)createChatPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags {
95 | [self createChatPost:title body:body tags:tags success:nil cancel:nil];
96 | }
97 |
98 | + (void)createChatPost:(NSString *)title body:(NSString *)body tags:(NSArray *)tags success:(NSURL *)successURL
99 | cancel:(NSURL *)cancelURL {
100 | NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
101 | [params setValue:title forKey:@"title"];
102 | [params setValue:body forKey:@"body"];
103 | [params setValue:tags forKey:@"tags"];
104 |
105 | [self performAction:@"chat" parameters:params success:successURL cancel:cancelURL];
106 | }
107 |
108 | #pragma mark - Private
109 |
110 | + (void)performAction:(NSString *)action parameters:(NSDictionary *)parameters {
111 | [self performAction:action parameters:parameters success:nil cancel:nil];
112 | }
113 |
114 | + (void)performAction:(NSString *)action parameters:(NSDictionary *)parameters success:(NSURL *)successURL cancel:(NSURL *)cancelURL {
115 | if ([self isTumblrInstalled]) {
116 | NSMutableDictionary *mutableParameters = [[NSMutableDictionary alloc] initWithDictionary:parameters];
117 | [mutableParameters setValue:@"TMTumblrSDK" forKey:@"referrer"];
118 | [mutableParameters setValue:[successURL absoluteString] forKey:@"x-success"];
119 | [mutableParameters setValue:[cancelURL absoluteString] forKey:@"x-cancel"];
120 |
121 | NSString *URLString = [NSString stringWithFormat:@"tumblr://x-callback-url/%@?%@", action,
122 | TMDictionaryToQueryString(mutableParameters)];
123 |
124 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:URLString]];
125 | }
126 | }
127 |
128 | @end
129 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Authentication/TMOAuth.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMOAuth.h
3 | // TumblrAuthentication
4 | //
5 | // Created by Bryan Irace on 11/19/12.
6 | // Copyright (c) 2012 Tumblr. All rights reserved.
7 | //
8 |
9 | @interface TMOAuth : NSObject
10 |
11 | /// Base string used to generate the OAuth signature
12 | @property (nonatomic, strong, readonly) NSString *baseString;
13 |
14 | /// Authentication header value
15 | @property (nonatomic, strong, readonly) NSString *headerString;
16 |
17 | /**
18 | Build an authentication header for a Tumblr API request.
19 |
20 | @param URL API request URL
21 | @param method HTTP method (GET or POST)
22 | @param postParameters POST body parameters
23 | @param nonce Unique request identifier
24 | @param consumerKey OAuth consumer key
25 | @param consumerSecret OAuth consumer secret
26 | @param token OAuth user token
27 | @param tokenSecret OAuth user secret
28 | */
29 | - (id)initWithURL:(NSURL *)URL method:(NSString *)method postParameters:(NSDictionary *)postParameters
30 | nonce:(NSString *)nonce consumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret
31 | token:(NSString *)token tokenSecret:(NSString *)tokenSecret;
32 |
33 | /// Convenience method for generating an OAuth header string
34 | + (NSString *)headerForURL:(NSURL *)URL method:(NSString *)method postParameters:(NSDictionary *)postParameters
35 | nonce:(NSString *)nonce consumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret
36 | token:(NSString *)token tokenSecret:(NSString *)tokenSecret;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Authentication/TMOAuth.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMOAuth.m
3 | // TumblrAuthentication
4 | //
5 | // Created by Bryan Irace on 11/19/12.
6 | // Copyright (c) 2012 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMOAuth.h"
10 |
11 | #import
12 | #import
13 | #import
14 | #import "TMSDKFunctions.h"
15 |
16 | #ifndef __IPHONE_7_0
17 | @interface NSData (NSDeprecated)
18 | // This method was retroactively made public as of iOS 7.
19 | // https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Classes/NSData_Class/DeprecationAppendix/AppendixADeprecatedAPI.html#//apple_ref/doc/uid/20000172-SW39
20 | - (NSString *)base64Encoding;
21 | @end
22 | #endif
23 |
24 | @interface TMOAuth()
25 |
26 | NSString *generateBaseString(NSString *baseURL, NSString *method, NSDictionary *headers, NSDictionary *queryParameters,
27 | NSDictionary *postParameters);
28 |
29 | NSString *sign(NSString *baseString, NSString *consumerSecret, NSString *tokenSecret);
30 |
31 | NSString *UNIXTimestamp(NSDate *date);
32 |
33 | NSData *HMACSHA1(NSString *dataString, NSString *keyString);
34 |
35 | @end
36 |
37 |
38 | @implementation TMOAuth
39 |
40 | + (NSString *)headerForURL:(NSURL *)URL method:(NSString *)method postParameters:(NSDictionary *)postParameters
41 | nonce:(NSString *)nonce consumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret
42 | token:(NSString *)token tokenSecret:(NSString *)tokenSecret {
43 | TMOAuth *auth = [[TMOAuth alloc] initWithURL:URL method:method postParameters:postParameters nonce:nonce
44 | consumerKey:consumerKey consumerSecret:consumerSecret token:token tokenSecret:tokenSecret];
45 | return auth.headerString;
46 | }
47 |
48 | - (id)initWithURL:(NSURL *)URL method:(NSString *)method postParameters:(NSDictionary *)postParameters
49 | nonce:(NSString *)nonce consumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret
50 | token:(NSString *)token tokenSecret:(NSString *)tokenSecret {
51 | if (self = [super init]) {
52 | NSMutableDictionary *headerParameters = [[NSMutableDictionary alloc] initWithDictionary:@{
53 | @"oauth_timestamp" : UNIXTimestamp([NSDate date]),
54 | @"oauth_nonce" : nonce,
55 | @"oauth_version" : @"1.0",
56 | @"oauth_signature_method" : @"HMAC-SHA1",
57 | @"oauth_consumer_key" : consumerKey,
58 | }];
59 |
60 | if (token && token.length > 0)
61 | headerParameters[@"oauth_token"] = token;
62 |
63 | NSDictionary *queryParameters = TMQueryStringToDictionary(URL.query);
64 |
65 | NSString *baseURLString = [[URL absoluteString] componentsSeparatedByString:@"?"][0];
66 |
67 | NSString *baseString = generateBaseString(baseURLString, method, headerParameters, queryParameters, postParameters);
68 |
69 | _baseString = baseString;
70 |
71 | headerParameters[@"oauth_signature"] = sign(baseString, consumerSecret, tokenSecret);
72 |
73 | NSMutableArray *components = [NSMutableArray array];
74 |
75 | for (NSString *key in headerParameters)
76 | [components addObject:[NSString stringWithFormat:@"%@=\"%@\"", key, TMURLEncode(headerParameters[key])]];
77 |
78 | _headerString = [NSString stringWithFormat:@"OAuth %@", [components componentsJoinedByString:@","]];
79 | }
80 |
81 | return self;
82 | }
83 |
84 | #pragma mark - Private
85 |
86 | NSString *generateBaseString(NSString *baseURL, NSString *method, NSDictionary *headers, NSDictionary *queryParameters,
87 | NSDictionary *postParameters) {
88 | NSMutableDictionary *signatureParameters = [NSMutableDictionary dictionaryWithDictionary:headers];
89 | [signatureParameters addEntriesFromDictionary:queryParameters];
90 | [signatureParameters addEntriesFromDictionary:postParameters];
91 |
92 | NSString *parameterString = TMDictionaryToQueryString(signatureParameters);
93 |
94 | return [NSString stringWithFormat:@"%@&%@&%@", method, TMURLEncode(baseURL), TMURLEncode(parameterString)];
95 | }
96 |
97 | NSString *sign(NSString *baseString, NSString *consumerSecret, NSString *tokenSecret) {
98 | NSString *keyString = [NSString stringWithFormat:@"%@&%@", consumerSecret, tokenSecret ? tokenSecret : @""];
99 |
100 | NSData *hashedData = HMACSHA1(baseString, keyString);
101 | NSString *base64EncodedString = nil;
102 |
103 | if ([hashedData respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
104 | base64EncodedString = [hashedData base64EncodedStringWithOptions:0];
105 | } else {
106 | base64EncodedString = [hashedData base64Encoding];
107 | }
108 |
109 | return base64EncodedString;
110 | }
111 |
112 | NSString *UNIXTimestamp(NSDate *date) {
113 | return [NSString stringWithFormat:@"%f", round([date timeIntervalSince1970])];
114 | }
115 |
116 | NSData *HMACSHA1(NSString *dataString, NSString *keyString) {
117 | NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
118 | NSData *key = [keyString dataUsingEncoding:NSUTF8StringEncoding];
119 |
120 | void *buffer = malloc(CC_SHA1_DIGEST_LENGTH);
121 | CCHmac(kCCHmacAlgSHA1, [key bytes], [key length], [data bytes], [data length], buffer);
122 |
123 | return [NSData dataWithBytesNoCopy:buffer length:CC_SHA1_DIGEST_LENGTH freeWhenDone:YES];
124 | }
125 |
126 | @end
127 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Authentication/TMTumblrAuthenticator.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMTumblrAuthenticator.h
3 | // TumblrAuthentication
4 | //
5 | // Created by Bryan Irace on 11/19/12.
6 | // Copyright (c) 2012 Tumblr. All rights reserved.
7 | //
8 |
9 | typedef void (^TMAuthenticationCallback)(NSString *, NSString *, NSError *);
10 |
11 | /**
12 | Provides three-legged OAuth and xAuth implementations for authenticating with the Tumblr API.
13 | */
14 | @interface TMTumblrAuthenticator : NSObject
15 |
16 | /// OAuth consumer key. Must be set prior to authenticating or making any API requests.
17 | @property (nonatomic, copy) NSString *OAuthConsumerKey;
18 |
19 | /// OAuth consumer key. Must be set prior to authenticating or making any API requests.
20 | @property (nonatomic, copy) NSString *OAuthConsumerSecret;
21 |
22 | + (TMTumblrAuthenticator *)sharedInstance;
23 |
24 | /**
25 | Authenticate via three-legged OAuth.
26 |
27 | Your `TMTumblrAuthenticator` instance's `handleOpenURL:` method must also be called from your `UIApplicationDelegate`'s
28 | `application:openURL:sourceApplication:annotation:` method in order to receive the tokens.
29 |
30 | @param URLScheme a URL scheme that your application can handle requests to.
31 | */
32 | - (void)authenticate:(NSString *)URLScheme callback:(TMAuthenticationCallback)callback;
33 |
34 | /**
35 | Authenticate via three-legged OAuth. This should be called from your `UIApplicationDelegate`'s
36 | `application:openURL:sourceApplication:annotation:` method in order to receive the tokens.
37 |
38 | This method is the last part of the authentication flow started by calling `authenticate:callback:`
39 | */
40 | - (BOOL)handleOpenURL:(NSURL *)url;
41 |
42 | /**
43 | Authenticate via xAuth.
44 |
45 | Please note that xAuth access [must be specifically requested](http://www.tumblr.com/oauth/apps) for your application.
46 | */
47 | - (void)xAuth:(NSString *)emailAddress password:(NSString *)password callback:(TMAuthenticationCallback)callback;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Authentication/TMTumblrAuthenticator.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMTumblrAuthenticator.m
3 | // TumblrAuthentication
4 | //
5 | // Created by Bryan Irace on 11/19/12.
6 | // Copyright (c) 2012 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMTumblrAuthenticator.h"
10 |
11 | #import "TMOAuth.h"
12 | #import "TMSDKFunctions.h"
13 |
14 | #if __IPHONE_OS_VERSION_MIN_REQUIRED
15 | #import
16 | #else
17 | #import
18 | #endif
19 |
20 | typedef void (^NSURLConnectionCompletionHandler)(NSURLResponse *, NSData *, NSError *);
21 |
22 | @interface TMTumblrAuthenticator()
23 |
24 | @property (nonatomic, copy) TMAuthenticationCallback threeLeggedOAuthCallback;
25 | @property (nonatomic, copy) NSString *threeLeggedOAuthTokenSecret;
26 |
27 | NSMutableURLRequest *mutableRequestWithURLString(NSString *URLString);
28 |
29 | NSError *errorWithStatusCode(NSInteger statusCode);
30 |
31 | NSDictionary *formEncodedDataToDictionary(NSData *data);
32 |
33 | @end
34 |
35 | @implementation TMTumblrAuthenticator
36 |
37 | + (id)sharedInstance {
38 | static TMTumblrAuthenticator *instance;
39 | static dispatch_once_t predicate;
40 | dispatch_once(&predicate, ^{ instance = [[TMTumblrAuthenticator alloc] init]; });
41 | return instance;
42 | }
43 |
44 | - (void)authenticate:(NSString *)URLScheme callback:(TMAuthenticationCallback)callback {
45 | // Clear token secret in case authentication was previously started but not finished
46 | self.threeLeggedOAuthTokenSecret = nil;
47 |
48 | NSString *tokenRequestURLString = [NSString stringWithFormat:@"http://www.tumblr.com/oauth/request_token?oauth_callback=%@",
49 | TMURLEncode([NSString stringWithFormat:@"%@://tumblr-authorize", URLScheme])];
50 |
51 | NSMutableURLRequest *request = mutableRequestWithURLString(tokenRequestURLString);
52 | [[self class] signRequest:request withParameters:nil consumerKey:self.OAuthConsumerKey
53 | consumerSecret:self.OAuthConsumerSecret token:nil tokenSecret:nil];
54 |
55 | NSURLConnectionCompletionHandler handler = ^(NSURLResponse *response, NSData *data, NSError *error) {
56 | if (error) {
57 | if (callback) {
58 | callback(nil, nil, error);
59 | }
60 |
61 | return;
62 | }
63 |
64 | NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
65 |
66 | if (statusCode == 200) {
67 | self.threeLeggedOAuthCallback = callback;
68 |
69 | NSDictionary *responseParameters = formEncodedDataToDictionary(data);
70 | self.threeLeggedOAuthTokenSecret = responseParameters[@"oauth_token_secret"];
71 |
72 | NSURL *authURL = [NSURL URLWithString:
73 | [NSString stringWithFormat:@"https://www.tumblr.com/oauth/authorize?oauth_token=%@",
74 | responseParameters[@"oauth_token"]]];
75 |
76 | #if __IPHONE_OS_VERSION_MIN_REQUIRED
77 | [[UIApplication sharedApplication] openURL:authURL];
78 | #else
79 | [[NSWorkspace sharedWorkspace] openURL:authURL];
80 | #endif
81 |
82 | } else {
83 | if (callback) {
84 | callback(nil, nil, errorWithStatusCode(statusCode));
85 | }
86 | }
87 | };
88 |
89 | [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:handler];
90 | }
91 |
92 | - (BOOL)handleOpenURL:(NSURL *)url {
93 | if (![url.host isEqualToString:@"tumblr-authorize"]) {
94 | return NO;
95 | }
96 |
97 | void(^clearState)() = ^ {
98 | self.threeLeggedOAuthTokenSecret = nil;
99 | self.threeLeggedOAuthCallback = nil;
100 | };
101 |
102 | NSDictionary *URLParameters = TMQueryStringToDictionary(url.query);
103 |
104 | if ([[URLParameters allKeys] count] == 0) {
105 | if (self.threeLeggedOAuthCallback) {
106 | self.threeLeggedOAuthCallback(nil, nil, [NSError errorWithDomain:@"Permission denied by user" code:0 userInfo:nil]);
107 | }
108 |
109 | clearState();
110 |
111 | return NO;
112 | }
113 |
114 | NSString *OAuthToken = URLParameters[@"oauth_token"];
115 |
116 | NSDictionary *requestParameters = @{ @"oauth_verifier" : URLParameters[@"oauth_verifier"] };
117 |
118 | NSMutableURLRequest *request = mutableRequestWithURLString(@"https://www.tumblr.com/oauth/access_token");
119 | request.HTTPMethod = @"POST";
120 | request.HTTPBody = [TMDictionaryToQueryString(requestParameters) dataUsingEncoding:NSUTF8StringEncoding];
121 |
122 | [[self class] signRequest:request withParameters:requestParameters consumerKey:self.OAuthConsumerKey
123 | consumerSecret:self.OAuthConsumerSecret token:OAuthToken tokenSecret:self.threeLeggedOAuthTokenSecret];
124 |
125 | NSURLConnectionCompletionHandler handler = ^(NSURLResponse *response, NSData *data, NSError *error) {
126 | if (error) {
127 | if (self.threeLeggedOAuthCallback) {
128 | self.threeLeggedOAuthCallback(nil, nil, error);
129 | }
130 | } else {
131 | NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
132 |
133 | if (self.threeLeggedOAuthCallback) {
134 | if (statusCode == 200) {
135 | NSDictionary *responseParameters = formEncodedDataToDictionary(data);
136 |
137 | self.threeLeggedOAuthCallback(responseParameters[@"oauth_token"], responseParameters[@"oauth_token_secret"], nil);
138 |
139 | } else {
140 | self.threeLeggedOAuthCallback(nil, nil, errorWithStatusCode(statusCode));
141 | }
142 | }
143 | }
144 |
145 | clearState();
146 | };
147 |
148 | [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:handler];
149 |
150 | return YES;
151 | }
152 |
153 | - (void)xAuth:(NSString *)emailAddress password:(NSString *)password callback:(TMAuthenticationCallback)callback {
154 | NSDictionary *requestParameters = @{
155 | @"x_auth_username" : emailAddress,
156 | @"x_auth_password" : password,
157 | @"x_auth_mode" : @"client_auth",
158 | @"api_key" : self.OAuthConsumerKey
159 | };
160 |
161 | NSMutableURLRequest *request = mutableRequestWithURLString(@"https://www.tumblr.com/oauth/access_token");
162 | request.HTTPMethod = @"POST";
163 | request.HTTPBody = [TMDictionaryToQueryString(requestParameters) dataUsingEncoding:NSUTF8StringEncoding];
164 |
165 | [[self class] signRequest:request withParameters:requestParameters consumerKey:self.OAuthConsumerKey
166 | consumerSecret:self.OAuthConsumerSecret token:nil tokenSecret:nil];
167 |
168 | NSURLConnectionCompletionHandler handler = ^(NSURLResponse *response, NSData *data, NSError *error) {
169 | if (error) {
170 | if (callback) {
171 | callback(nil, nil, error);
172 | }
173 |
174 | return;
175 | }
176 |
177 | NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
178 |
179 | if (statusCode == 200) {
180 | NSDictionary *responseParameters = formEncodedDataToDictionary(data);
181 |
182 | if (callback) {
183 | callback(responseParameters[@"oauth_token"], responseParameters[@"oauth_token_secret"], nil);
184 | }
185 |
186 | } else {
187 | if (callback) {
188 | callback(nil, nil, errorWithStatusCode(statusCode));
189 | }
190 | }
191 | };
192 |
193 | [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:handler];
194 | }
195 |
196 | #pragma mark - NSObject
197 |
198 |
199 | #pragma mark - Helpers
200 |
201 | + (void)signRequest:(NSMutableURLRequest *)request
202 | withParameters:(NSDictionary *)parameters
203 | consumerKey:(NSString *)consumerKey
204 | consumerSecret:(NSString *)consumerSecret
205 | token:(NSString *)OAuthToken
206 | tokenSecret:(NSString *)OAuthTokenSecret {
207 | [request setValue:@"TMTumblrSDK" forHTTPHeaderField:@"User-Agent"];
208 |
209 | [request setValue:[TMOAuth headerForURL:request.URL
210 | method:request.HTTPMethod
211 | postParameters:parameters
212 | nonce:[[NSProcessInfo processInfo] globallyUniqueString]
213 | consumerKey:consumerKey
214 | consumerSecret:consumerSecret
215 | token:OAuthToken
216 | tokenSecret:OAuthTokenSecret] forHTTPHeaderField:@"Authorization"];
217 | }
218 |
219 | NSMutableURLRequest *mutableRequestWithURLString(NSString *URLString) {
220 | return [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URLString]];
221 | }
222 |
223 | NSError *errorWithStatusCode(NSInteger statusCode) {
224 | return [NSError errorWithDomain:@"Authentication request failed" code:statusCode userInfo:nil];
225 | }
226 |
227 | NSDictionary *formEncodedDataToDictionary(NSData *data) {
228 | NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
229 | NSDictionary *dictionary = TMQueryStringToDictionary(string);
230 |
231 | return dictionary;
232 | }
233 |
234 | @end
235 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Core/TMSDKFunctions.h:
--------------------------------------------------------------------------------
1 | //
2 | // TMSDKFunctions.h
3 | // TMTumblrSDK
4 | //
5 | // Created by Bryan Irace on 3/24/13.
6 | // Copyright (c) 2013 Tumblr. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface TMSDKFunctions : NSObject
12 |
13 | NSString *TMURLDecode(NSString *string);
14 |
15 | NSString *TMURLEncode(NSString *string);
16 |
17 | NSDictionary *TMQueryStringToDictionary(NSString *query);
18 |
19 | NSString *TMDictionaryToQueryString(NSDictionary *dictionary);
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/Pods/TMTumblrSDK/TMTumblrSDK/Core/TMSDKFunctions.m:
--------------------------------------------------------------------------------
1 | //
2 | // TMSDKFunctions.m
3 | // TMTumblrSDK
4 | //
5 | // Created by Bryan Irace on 3/24/13.
6 | // Copyright (c) 2013 Tumblr. All rights reserved.
7 | //
8 |
9 | #import "TMSDKFunctions.h"
10 |
11 | @implementation TMSDKFunctions
12 |
13 | NSString *TMURLDecode(NSString *string) {
14 | return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapes(NULL, (CFStringRef)string,
15 | CFSTR("")));
16 | }
17 |
18 | NSString *TMURLEncode(id value) {
19 | NSString *string;
20 |
21 | if ([value isKindOfClass:[NSString class]])
22 | string = (NSString *)value;
23 | else
24 | string = [value stringValue];
25 |
26 | return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)string, NULL,
27 | CFSTR("!*'();:@&=+$,/?%#[]%"), kCFStringEncodingUTF8));
28 | }
29 |
30 | NSDictionary *TMQueryStringToDictionary(NSString *query) {
31 | NSMutableDictionary *mutableParameterDictionary = [[NSMutableDictionary alloc] init];
32 |
33 | NSArray *parameters = [query componentsSeparatedByString:@"&"];
34 |
35 | for (NSString *parameter in parameters) {
36 | NSArray *keyValuePair = [parameter componentsSeparatedByString:@"="];
37 |
38 | if (keyValuePair.count == 2) {
39 | NSString *key = TMURLDecode(keyValuePair[0]);
40 | NSString *value = TMURLDecode(keyValuePair[1]);
41 |
42 | id existingValueForKey = mutableParameterDictionary[key];
43 |
44 | if (existingValueForKey) {
45 | if ([existingValueForKey isKindOfClass:[NSMutableArray class]])
46 | [(NSMutableArray *)existingValueForKey addObject:value];
47 | else
48 | [mutableParameterDictionary setObject:[NSMutableArray arrayWithObjects:existingValueForKey, value, nil]
49 | forKey:key];
50 | } else
51 | [mutableParameterDictionary setObject:value forKey:key];
52 | }
53 | }
54 |
55 | return [NSDictionary dictionaryWithDictionary:mutableParameterDictionary];
56 | }
57 |
58 | NSString *TMDictionaryToQueryString(NSDictionary *dictionary) {
59 | NSMutableArray *parameters = [NSMutableArray array];
60 |
61 | void (^addParameter)(NSString *key, NSString *value) = ^(NSString *key, NSString *value) {
62 | [parameters addObject:[NSString stringWithFormat:@"%@=%@", TMURLEncode(key), TMURLEncode(value)]];
63 | };
64 |
65 | for (NSString *key in [[dictionary allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]) {
66 | id value = dictionary[key];
67 |
68 | if ([value isKindOfClass:[NSArray class]]) {
69 | for (NSString *arrayValue in (NSArray *)value)
70 | addParameter(key, arrayValue);
71 | } else
72 | addParameter(key, value);
73 | }
74 |
75 | return [parameters componentsJoinedByString:@"&"];
76 | }
77 |
78 | @end
79 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Core Data Example
2 |
3 | This is a sample project whose purpose is to gather feedback on the best way to use Core Data in a multithreaded environment. Here's a [blog post](http://bryan.io/post/89082476661/core-data-sample-project) explaining the motivation:
4 |
5 | > We’ve been using Core Data for persistence in [Tumblr for iOS](https://itunes.apple.com/us/app/tumblr/id305343404) for years now, but are always interested in re-evaluating our approach to make sure that we’re leveraging the SDK as effectively as possible.
6 |
7 | The focal point is the [TMCoreDataController](https://github.com/tumblr/CoreDataExample/blob/master/CoreDataExample/TMCoreDataController.h) class, which exposes a block-based API for updating managed object contexts both from the main queue as well as in the background.
8 |
9 | The application simply fetches, persists, and displays a little bit of data from the Tumblr API, in order to provide a real-world example of how `TMCoreDataController` is expected to be used.
10 |
11 | If you have any feedback, please create [issues](https://github.ewr01.tumblr.net/bryan/CoreDataExample/issues) or [pull requests](https://github.ewr01.tumblr.net/bryan/CoreDataExample/pulls). Thanks for taking a look!
12 |
13 | ## Approach
14 |
15 | `TMCoreDataController` is implemented using three-levels of parent/child managed object contexts (based off of the suggestions made in [this blog post](http://floriankugler.com/blog/2013/4/2/the-concurrent-core-data-stack)):
16 |
17 | * **Master** context (private queue concurrency type) – long lived
18 | * **Main** context (main queue concurrency type) – long lived
19 | * **Background** contexts (private queue concurrency type) – a new one created each time
20 |
21 | Write operations should only be done through `TMCoreDataController`'s `performBackgroundBlockAndWait:` and `performMainContextBlock:` methods, both of which save the context being written to as well as any parent contexts (recursively) immediately after.
22 |
23 | ### Thought process
24 |
25 | * Disk writes are slow, so we want them to happen off of the main thread. Hence writing to disk occurs in the background when the master context is saved.
26 | * Main context is written to and read from on the main queue via interaction with user interface.
27 | * Background updates (e.g. updating our Core Data database off the back of network requests) occur on a background context. A new background context is created each time to make sure they are up to date.
28 | * Background context is a child of the main context such that the UI is updated after our background changes are saved.
29 | * When a managed object context is saved, its parent context(s) are also saved, recursively, so ensure that all of our changes are written to disk.
30 |
31 | In this particular example, the “heavy lifting” of updating our database with new posts is done in `TMDashboardViewController`'s `refresh` method. The code in this particular project is pretty simple and contrived, but assume that a lot more work would be done here in a real production app. It is expected that user interaction may result in updates to the main queue's context while this background block is being executed.
32 |
33 | ## Running CoreDataExample
34 |
35 | To run the sample application, you need to add OAuth keys, tokens, and secrets to [TMAppDelegate](https://github.com/tumblr/CoreDataExample/blob/master/CoreDataExample/TMAppDelegate.m#L24). If you don't already have one, you can create a Tumblr API application [here](https://www.tumblr.com/oauth/apps) and generate a token and secret using our [API console](https://api.tumblr.com/console).
36 |
37 | ## Questions
38 |
39 | What problems are there with this approach? How could this be improved?
40 |
41 | Specifically:
42 |
43 | * Is the recursive managed object context save the best way to ensure that all of our data is kept in sync?
44 |
45 | * I'm worried that this architecture makes us susceptible to deadlocks, as outlined in [this article](http://wbyoung.tumblr.com/post/27851725562/core-data-growing-pains):
46 |
47 | > With NSFetchedResultsController and nested contexts, it’s pretty easy to do. Using the same UIManagedDocument setup described above, executing fetch requests in the private queue context while using NSFetchedResultsController with the main queue context will likely deadlock. If you start both at about the same time it happens with almost 100% consistency. NSFetchedResultsController is probably acquiring a lock that it shouldn’t be. This has been reported as fixed for an upcoming release of iOS.
48 |
49 | Unfortunately I've seen a couple of crashes which may corroborate the above, such as:
50 |
51 | Incident Identifier: 5168BD71-BFD2-4DF6-84C4-240364B888DD
52 | CrashReporter Key: 289E38A8-3E8A-41CB-877F-1FEEF852AF30
53 | Hardware Model: iPhone6,1
54 | Version: 251
55 | Code Type: ARM-64
56 | Parent Process: launchd [1]
57 |
58 | Date/Time: 2014-05-13T01:23:26Z
59 | OS Version: iPhone OS 7.1.1 (11D201)
60 | Report Version: 104
61 |
62 | Exception Type: SIGSEGV
63 | Exception Codes: SEGV_ACCERR at 0xbf02beb8
64 | Crashed Thread: 0
65 |
66 | Application Specific Information:
67 | objc_msgSend() selector name: isFault
68 |
69 | Thread 0 Crashed:
70 | 0 libobjc.A.dylib 0x00000001978fc1d0 objc_msgSend + 16
71 | 1 CoreData 0x000000018b1782a8 __92-[NSManagedObjectContext(_NestedContextSupport) newValuesForObjectWithID:withContext:error:]_block_invoke + 276
72 | 2 libdispatch.dylib 0x0000000197ec3fd4 _dispatch_client_callout + 12
73 | 3 libdispatch.dylib 0x0000000197ec9c84 _dispatch_barrier_sync_f_invoke + 44
74 | 4 CoreData 0x000000018b16ccec _perform + 120
75 | 5 CoreData 0x000000018b178150 -[NSManagedObjectContext(_NestedContextSupport) newValuesForObjectWithID:withContext:error:] + 124
76 | 6 CoreData 0x000000018b0e8b00 _PFFaultHandlerLookupRow + 356
77 | 7 CoreData 0x000000018b0e8604 _PF_FulfillDeferredFault + 252
78 | 8 CoreData 0x000000018b0e8458 _sharedIMPL_pvfk_core + 60
79 | 9 ExampleApplication 0x00000001000887cc 0x100054000 + 214988
80 | 10 ExampleApplication 0x00000001000625c0 0x100054000 + 58816
81 | 11 libdispatch.dylib 0x0000000197ec4014 _dispatch_call_block_and_release + 20
82 | 12 libdispatch.dylib 0x0000000197ec3fd4 _dispatch_client_callout + 12
83 | 13 libdispatch.dylib 0x0000000197ec9ea8 _dispatch_after_timer_callback + 76
84 | 14 libdispatch.dylib 0x0000000197ec3fd4 _dispatch_client_callout + 12
85 | 15 libdispatch.dylib 0x0000000197ec5b90 _dispatch_source_invoke + 496
86 | 16 libdispatch.dylib 0x0000000197ec7180 _dispatch_main_queue_callback_4CF + 240
87 | 17 CoreFoundation 0x000000018b3a2c2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
88 | 18 CoreFoundation 0x000000018b3a0f6c __CFRunLoopRun + 1448
89 | 19 CoreFoundation 0x000000018b2e1c20 CFRunLoopRunSpecific + 448
90 | 20 GraphicsServices 0x0000000190fc9c0c GSEventRunModal + 164
91 | 21 UIKit 0x000000018e412fdc UIApplicationMain + 1152
92 | 22 ExampleApplication 0x000000010005df3c 0x100054000 + 40764
93 | 23 libdyld.dylib 0x0000000197edfaa0 start + 0
94 |
95 | How can this be mitigated, other than just optimizing all of our fetches and saves to prevent the persistent store coordinator from being locked for longer than it needs to be?
96 |
97 | ### Marcus Zarra's suggestions for how to prevent deadlocks (thanks for your feedback, Marcus!)
98 |
99 | * [“Long fetch, long save, long activity to the PSC locks it. Simple rule, don't lock the PSC for a long time.”](https://twitter.com/mzarra/status/466302788863938560)
100 | * [“Smaller saves during the import, more intelligent fetching for your update/insert question. Those are the normal first pass items.”](https://twitter.com/mzarra/status/466304487859048448)
101 | * [“Doing a count instead of a fetch, fetching ids only, predicate performance, batch size, things like that can make a huge difference.”](https://twitter.com/mzarra/status/466316613227409408)
102 |
103 | Marcus provides a *ton* of free Core Data help on Stack Overflow as well as on Twitter, you should support him by checking out his [Core Data book](http://pragprog.com/book/mzcd2/core-data).
104 |
105 | ## Thank you!
106 |
107 | Bryan Irace ([Email](mailto:bryan@tumblr.com), [Twitter](http://twitter.com/irace))
108 |
109 |
--------------------------------------------------------------------------------