Screenshot++

Screenshot++ 1.2 Now Available

I'm pleased to announce that Screenshot++ 1.2 is now available on the App Store! It includes support for screenshots from Apple Watch, Quick Actions for automating complex actions, keyboard shortcuts, and UI enhancements.

A big thank you to all our beta testers for their valuable feedback! If you would like to help the next version of Screenshot++, we'll be running another beta for our next version soon.

Screenshot++ 2.0 is already in development with support for new features in iOS 9 as well as a new Dashboard. Stay tuned for more info!

If you love Screenshot++, please take a moment to rate and review us in the App Store. It really helps!

Learn more about Screenshot++

Screenshot++ 1.0 for iOS - Now Available

 
 

I'm pleased to announce that Screenshot++ has launched on the App Store, available for both iPhone and iPad as a universal app.

Screenshot++ help you quickly organize or delete the screenshots on your device and includes Private Storage with sync for screenshots you want to keep separate from your Photo Library.

I'd like to thank our fantastic beta testers that have provided excellent feedback while Screenshot++ was in beta!

If you're a member of the press, you can find the Press Pack for Screenshot++ here.

You can follow Screenshot++ on Twitter by following @screenshot_app for the latest news and updates about the app.

Check out Screenshot++ on the App Store!

Creating App Store Preview Videos

I've spent the better part of a day creating the first app preview video for Screenshot++, which I hope to launch in the next week or so.

Record your app in action on an iOS device using Quicktime in Yosemite, import the video footage into iMovie, create an App Preview project and start editing. Pretty simple so far.

I created a short soundtrack for the preview in Garageband and added it to the iMovie project. Export and upload to iTunes Connect. Done, right?

I uploaded the video to iTunes Connect under the "4-inch" tab. Then, I went to the "5.5-inch" tab and the preview wasn't there. Why not?

The docs reveal that you're supposed to upload a video for each iPhone resolution (that's 3). But, I don't have an iPhone 6 Plus, so now what?

After some digging, it turns out that Apple prefers videos in each resolution but will provide one version to all devices when viewing in the App Store if you only provide one. This isn't documented anywhere I could find but I'm trusting the good people on stack overflow.

Why not just export from iMovie in each resolution? That was my thought, but alas, iMovie doesn't give you that option. There is also no reasonable way to use Quicktime's screen recording feature with the iOS simulator.

So for Screenshot++ 1.0, I've uploaded a Preview view each for iPhone and iPad. We'll know after the app launches if the video is viewable on all modern iPhones.

Developing for CloudKit - Part 3

Read Part 1 in series on Developing for CloudKit

Read Part 2 in series on Developing for CloudKit

In the 6 weeks since my last post on CloudKit Development, I’ve added the ability to make changes to a CKRecord and have those changes synced between devices. In this post, I'll cover syncing changes and data considerations.


The CKRecord from the previous posts had an image property that never changed after upload to CloudKit. Since then, I’ve added 2 properties that will need their changes synced. The first is a boolean, the second is an array.

I began by making the fatal assumption about CKRecord’s recordChangeTag property. I believed I could use it to query the server for CKRecords with changes and download changes on the result - turns out I was way off the mark.

/* Change tags are updated by the server to a unique value every time a record is modified.
   A different change tag necessarily means that the contents of the record are different. */
@property (nonatomic, readonly, copy) NSString *recordChangeTag;

That’s not what recordChangeTag was intended for so I had to look for another solution.

That solution was CloudKit’s Push Notifications. Basically, you register the app for notifications and the device will receive a notification each time CKRecord is updated (you can register for delete/creation notifs too).

That was great and all, but what do you do with that notification?

First, I don’t want to start a sync session in a background task. Downloading CKRecords in the background would be acceptable if they were small (<50KB) but they’re at least 3MB each. I also want to plan ahead and account for CKRecords with assets over 25MB each.

My goal from the start was to keep the sync engine as light-weight as possible, with minimal network transfers.

The other issue with background syncing is having to load the full sync engine as a background process, meaning far more overhead than necessary. Yes, these are artificial constraints I’ve placed on the project, and many apps on the App Store cram far more into a background task, but I digress.

The solution was to create a singleton class that keeps track of the CKRecordID.recordNames from the notification. I load the singleton, check to see if the recordID has been previously added, add it to an array if it hasn’t, then save to disk. The whole process is fast and lightweight. When the app resumes, I can download change to the records stored in the singleton, then clear the list.

Every decision comes with trade-offs. In a perfect world, I would sync changes in a background session. Of course it’s better for the user’s data to be up to date each time they open the app. But for the sake of battery life, mobile data usage, and overall performance of the OS, I think it’s the worth the user waiting 1-3 seconds for sync to complete. It’s a tradeoff I’m willing to make.

If you’ve read the previous 2 posts, updating the data for changes happens at the end of the sync session, after local offline changes are synced. In the spirit of doing the least amount of work possible, we sync inserts and deletions before changes. Consider this scenario - there are 5 total objects, 3 are on the client (synced previouslly), 2 new objects need to be downloaded from the server, one local object needs to be deleted, all objects have changes. If we synced the changes first, we would be updating the 3 local objects. Instead, we should complete the local deletion first, resulting in only updating the 2 remaining objects.

That didn’t explain the entire sync process but it illustrates the types of considerations you’ll have to make. Saving the user 5-10KB here and there doesn’t seem like much now, but after 1,000 syncs, it adds up.

What about insert/deletion notifications?

These are good for your typical CloudKit-based app where the data is online-only. For an app that allows the user to make offline changes, you need to handle this yourself.


CloudKit wasn't intended to sync Core Data. It was designed as a backend, a way for app developers to focus on native apps and let Apple handle the server implementation and cost. The sync engine I created is a small layer that sits between Core Data and CloudKit.

I'm happy with the results so far. The next step is to abstract the sync layer so it's independent of your data model. I hope to open source it at some point in 2015.

Update: Screenshot++ has shipped with the CloudKit sync engine. Give it a spin!