Skip to content

Commit d7fae3d

Browse files
committed
CloudCaptions: How integrate CloudKit into your application: Version 1.0, 2014-09-17
First public release. This sample shows how to use CloudKit to upload and retrieve CKRecords and associated assets. In this example, there are two record types, an image record type and a post record type. Users are able to upload their own photos or select an image already found in an image record type. This example also uses an NSPredicate in its CKQueries to filter results based on tags. Signed-off-by: Liu Lantao <[email protected]>
1 parent 2ce554f commit d7fae3d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3289
-0
lines changed

CloudCaptions/Base.lproj/AAPLStoryboard.storyboard

+340
Large diffs are not rendered by default.

CloudCaptions/CloudCaptions.xcodeproj/project.pbxproj

+489
Large diffs are not rendered by default.

CloudCaptions/CloudCaptions.xcodeproj/project.xcworkspace/contents.xcworkspacedata

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "0600"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "E76EC7A5192D3D4100FFB105"
18+
BuildableName = "CloudCaptions.app"
19+
BlueprintName = "CloudCaptions"
20+
ReferencedContainer = "container:CloudCaptions.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
27+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
28+
shouldUseLaunchSchemeArgsEnv = "YES"
29+
buildConfiguration = "Debug">
30+
<Testables>
31+
</Testables>
32+
<MacroExpansion>
33+
<BuildableReference
34+
BuildableIdentifier = "primary"
35+
BlueprintIdentifier = "E76EC7A5192D3D4100FFB105"
36+
BuildableName = "CloudCaptions.app"
37+
BlueprintName = "CloudCaptions"
38+
ReferencedContainer = "container:CloudCaptions.xcodeproj">
39+
</BuildableReference>
40+
</MacroExpansion>
41+
</TestAction>
42+
<LaunchAction
43+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
44+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
45+
launchStyle = "0"
46+
useCustomWorkingDirectory = "NO"
47+
buildConfiguration = "Debug"
48+
ignoresPersistentStateOnLaunch = "NO"
49+
debugDocumentVersioning = "YES"
50+
allowLocationSimulation = "YES">
51+
<BuildableProductRunnable>
52+
<BuildableReference
53+
BuildableIdentifier = "primary"
54+
BlueprintIdentifier = "E76EC7A5192D3D4100FFB105"
55+
BuildableName = "CloudCaptions.app"
56+
BlueprintName = "CloudCaptions"
57+
ReferencedContainer = "container:CloudCaptions.xcodeproj">
58+
</BuildableReference>
59+
</BuildableProductRunnable>
60+
<AdditionalOptions>
61+
</AdditionalOptions>
62+
</LaunchAction>
63+
<ProfileAction
64+
shouldUseLaunchSchemeArgsEnv = "YES"
65+
savedToolIdentifier = ""
66+
useCustomWorkingDirectory = "NO"
67+
buildConfiguration = "Release"
68+
debugDocumentVersioning = "YES">
69+
<BuildableProductRunnable>
70+
<BuildableReference
71+
BuildableIdentifier = "primary"
72+
BlueprintIdentifier = "E76EC7A5192D3D4100FFB105"
73+
BuildableName = "CloudCaptions.app"
74+
BlueprintName = "CloudCaptions"
75+
ReferencedContainer = "container:CloudCaptions.xcodeproj">
76+
</BuildableReference>
77+
</BuildableProductRunnable>
78+
</ProfileAction>
79+
<AnalyzeAction
80+
buildConfiguration = "Debug">
81+
</AnalyzeAction>
82+
<ArchiveAction
83+
buildConfiguration = "Release"
84+
revealArchiveInOrganizer = "YES">
85+
</ArchiveAction>
86+
</Scheme>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
Copyright (C) 2014 Apple Inc. All Rights Reserved.
3+
See LICENSE.txt for this sample’s licensing information
4+
5+
Abstract:
6+
7+
Application Delegate for ImageMessages
8+
Registers for notifications and will notify the AAPLTableViewController when it receives an update
9+
10+
*/
11+
12+
@import UIKit;
13+
14+
@class AAPLTableViewController;
15+
16+
@interface AAPLAppDelegate : UIResponder <UIApplicationDelegate>
17+
18+
@property (strong, nonatomic) UIWindow *window;
19+
@property (weak) IBOutlet AAPLTableViewController *tableController;
20+
21+
@end
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright (C) 2014 Apple Inc. All Rights Reserved.
3+
See LICENSE.txt for this sample’s licensing information
4+
5+
*/
6+
7+
@import CloudKit;
8+
#import "AAPLAppDelegate.h"
9+
#import "AAPLTableViewController.h"
10+
11+
@interface AAPLAppDelegate ()
12+
@end
13+
14+
@implementation AAPLAppDelegate
15+
16+
17+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18+
// Override point for customization after application launch.
19+
UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:nil];
20+
[application registerUserNotificationSettings:notificationSettings];
21+
[application registerForRemoteNotifications];
22+
return YES;
23+
}
24+
25+
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
26+
{
27+
if(self.tableController)
28+
{
29+
// Sends the ID of the record save that triggered the push to the tableViewController
30+
CKQueryNotification *recordInfo = [CKQueryNotification notificationFromRemoteNotificationDictionary:userInfo];
31+
[self.tableController loadNewPostsWithRecordID:recordInfo.recordID];
32+
}
33+
}
34+
35+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
Copyright (C) 2014 Apple Inc. All Rights Reserved.
3+
See LICENSE.txt for this sample’s licensing information
4+
5+
Abstract:
6+
7+
Collection view that creates an AAPLExistingImageCollectionViewCell for each record added to its imageRecords array
8+
9+
10+
*/
11+
12+
@import CloudKit;
13+
@import UIKit;
14+
15+
@interface AAPLExistingImageCollectionView : UICollectionView <UICollectionViewDataSource>
16+
17+
@property (nonatomic, readonly) NSUInteger count;
18+
- (void) addImageFromRecord:(CKRecord *)toAdd;
19+
- (CKRecordID *) getRecordIDAtIndex:(NSIndexPath *)index;
20+
- (void) cellAtIndex:(NSIndexPath *)index isLoading:(BOOL)loading;
21+
22+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
Copyright (C) 2014 Apple Inc. All Rights Reserved.
3+
See LICENSE.txt for this sample’s licensing information
4+
5+
*/
6+
7+
#import "AAPLExistingImageCollectionView.h"
8+
#import "AAPLExistingImageCollectionViewCell.h"
9+
#import "AAPLImage.h"
10+
11+
static NSString * const cellReuseIdentifier = @"imageCell";
12+
13+
@interface AAPLExistingImageCollectionView()
14+
15+
@property (strong, atomic) NSMutableArray *imageRecords;
16+
@property (strong, atomic) dispatch_queue_t updateArrayQueue;
17+
@property (strong, atomic) NSIndexPath *currentLoadingIndex;
18+
19+
@end
20+
21+
22+
#pragma mark -
23+
24+
@implementation AAPLExistingImageCollectionView
25+
26+
- (instancetype) initWithCoder:(NSCoder *)aDecoder
27+
{
28+
self = [super initWithCoder:aDecoder];
29+
if(self)
30+
{
31+
self.dataSource = self;
32+
_imageRecords = [[NSMutableArray alloc] init];
33+
_updateArrayQueue = dispatch_queue_create("UpdateCollectionViewQueue", DISPATCH_QUEUE_SERIAL);
34+
}
35+
return self;
36+
}
37+
38+
- (NSUInteger) count
39+
{
40+
return [self.imageRecords count];
41+
}
42+
43+
- (void) addImageFromRecord:(CKRecord *)toAdd
44+
{
45+
AAPLImage *fetchedImage = [[AAPLImage alloc] initWithRecord:toAdd];
46+
// Ensures that only one object will be added to the imageRecords array at a time
47+
dispatch_async(self.updateArrayQueue, ^{
48+
[self.imageRecords addObject:fetchedImage];
49+
dispatch_async(dispatch_get_main_queue(), ^{
50+
[self reloadData];
51+
});
52+
});
53+
}
54+
55+
- (void) cellAtIndex:(NSIndexPath *)index isLoading:(BOOL)loading
56+
{
57+
if(loading == YES) self.currentLoadingIndex = index;
58+
else self.currentLoadingIndex = nil;
59+
60+
dispatch_async(dispatch_get_main_queue(), ^{
61+
[self reloadData];
62+
});
63+
}
64+
65+
- (CKRecordID *) getRecordIDAtIndex:(NSIndexPath *)index
66+
{
67+
// returns the recordID of the item in imageRecords at the given index
68+
AAPLImage *AAPLImageAtIndex = self.imageRecords[index.row];
69+
return [[AAPLImageAtIndex record] recordID];
70+
}
71+
72+
#pragma mark UICollectionViewDataSource
73+
- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
74+
{
75+
return [self.imageRecords count];
76+
}
77+
78+
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
79+
- (AAPLExistingImageCollectionViewCell *) collectionView:(AAPLExistingImageCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
80+
{
81+
AAPLExistingImageCollectionViewCell *cell = [self dequeueReusableCellWithReuseIdentifier:cellReuseIdentifier forIndexPath:indexPath];
82+
if (cell == nil)
83+
{
84+
cell = [[AAPLExistingImageCollectionViewCell alloc] init];
85+
}
86+
cell.thumbnailImage.image = [self.imageRecords[indexPath.row] thumbnail];
87+
if(indexPath && [indexPath isEqual:self.currentLoadingIndex]) [cell setLoading:YES];
88+
else [cell setLoading:NO];
89+
90+
return cell;
91+
}
92+
93+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Copyright (C) 2014 Apple Inc. All Rights Reserved.
3+
See LICENSE.txt for this sample’s licensing information
4+
5+
Abstract:
6+
7+
Custom collection view cell object used to display the thumbnail for the AAPLImage assigned to it
8+
9+
*/
10+
11+
@import UIKit;
12+
#import "AAPLImage.h"
13+
14+
@interface AAPLExistingImageCollectionViewCell : UICollectionViewCell
15+
16+
@property (strong, atomic) IBOutlet UIImageView *thumbnailImage;
17+
- (void) setLoading:(BOOL)loading;
18+
19+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
Copyright (C) 2014 Apple Inc. All Rights Reserved.
3+
See LICENSE.txt for this sample’s licensing information
4+
5+
*/
6+
7+
#import "AAPLExistingImageCollectionViewCell.h"
8+
9+
@interface AAPLExistingImageCollectionViewCell ()
10+
11+
@property (strong, nonatomic) IBOutlet UIActivityIndicatorView *loadingIndicator;
12+
@property (strong, atomic) UIVisualEffectView *blurSubview;
13+
14+
@end
15+
16+
17+
#pragma mark -
18+
19+
@implementation AAPLExistingImageCollectionViewCell
20+
21+
- (void) setLoading:(BOOL)loading
22+
{
23+
if(loading)
24+
{
25+
[self.loadingIndicator startAnimating];
26+
27+
UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
28+
self.blurSubview = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
29+
self.blurSubview.frame = self.thumbnailImage.frame;
30+
[self.thumbnailImage addSubview:self.blurSubview];
31+
}
32+
else
33+
{
34+
if(self.blurSubview)
35+
{
36+
[self.blurSubview removeFromSuperview];
37+
self.blurSubview = nil;
38+
}
39+
[self.loadingIndicator stopAnimating];
40+
}
41+
}
42+
43+
@end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
Copyright (C) 2014 Apple Inc. All Rights Reserved.
3+
See LICENSE.txt for this sample’s licensing information
4+
5+
Abstract:
6+
7+
Responsible for downloading the Image records and sending them to the AAPLExistingImageCollectionView
8+
Passes the selected AAPLImage to the AAPLTableViewController
9+
10+
*/
11+
12+
@import UIKit;
13+
@import CloudKit;
14+
15+
@class AAPLImage;
16+
17+
@interface AAPLExistingImageViewController : UIViewController
18+
19+
@property (weak, atomic) id delegate;
20+
21+
@end
22+
23+
// Delegate with method that returns the selected AAPLImage
24+
@protocol AAPLExistingImageViewControllerDelegate <NSObject>
25+
26+
@optional
27+
- (void) AAPLExisitingImageViewController:(AAPLExistingImageViewController *)controller selectedImage:(AAPLImage *)image;
28+
29+
@end

0 commit comments

Comments
 (0)