Recent Updates Toggle Comment Threads | Keyboard Shortcuts

  • Jay Versluis 11:17 am on September 18, 2014 Permalink | Reply
    Tags: iOS 8   

    What’s New in iOS 8 

    iOS-8-IconEven though us developers get access to new versions of iOS, it doesn’t mean that Apple actually tell us what’s new in a release. iOS 8 is no exception.

    When you upgrade on your device there’s a handy “Learn More” link that gives you a summary of the new features. I wish this was accessible to developers when the first beta comes out. Perhaps one day it will be, or it always has been and I’ve always missed the link.

    Until such time, here’s what’s new in iOS 8 (without the marketing hype):

    This update contains hundreds of new features, including the following:

    • Messages improvements
    • Tap to Talk to send your voice, a video or a photo with just a swipe
    • Group messaging options to name a conversation, add a contact, remove a contact, or leave a conversation
    • New details view with Do Not Disturb, location sharing and attachments view

    Photos improvements

    • Smart editing tools to adjust light and color with a swipe
    • Fine-tune controls to adjust exposure, brightness, contrast, highlights, shadows and more
    • Search by date, location, or album name or use smart suggestions
    • Smart albums for Slo-mo videos, Bursts, Panoramas, and Time-lapse
    • Third-party photo filters and editing tools supported directly in Photos
    • Your photos and metadata from iPhoto will be migrated to Photos. Books, Journals and Slideshows will be converted to albums containing only photos.
    • iPhoto for iOS is not supported on devices running iOS 8 or later.

    Camera improvements

    • Time-lapse mode
    • Capture timer
    • Adjust exposure with a simple nudge to lighten or darken a photo prior to capture
    • Burst mode on front facing camera on iPhone 5s
    • Panorama for iPad Air and iPad mini with Retina display

    QuickType keyboard

    • Predictive typing personalized to your writing style, and customized based on the recipient and the app
    • Predictive is available in English (Australia, Canada, UK, US), French (Canada, France, Switzerland), German (Germany, Switzerland), Italian, Portuguese (Brazil), Spanish, Thai
    • Third-party keyboard support

    Health

    • New Health app with easy-to-read dashboard of health and fitness data
    • Ability to share health data with apps to provide a more comprehensive way to manage your health and fitness
    • Add a Medical ID with information about allergies, medical conditions, and more with the option to make accessible from the lock screen
    • Available on iPhone and iPod touch

    Family Sharing

    • Share iTunes, iBooks, and App Store purchases with up to six members of your family.
    • Pay for family purchases with a single credit card and approve purchases by children with Ask to Buy
    • Easily share family photos, a family calendar, locations and more

    iCloud Drive

    • Store all your documents in iCloud and access them from your iPhone, iPad, iPod touch, Mac, or PC
    • Share the same file across multiple compatible apps
    • Edits you make on one device update on all your devices automatically
    • Continuity features so your iPhone, iPad, and Mac work together more seamlessly
    • Handoff to continue what you’re doing as you move from one device to another
    • Make and receive calls and send and receive SMS or MMS messages on your iPad or Mac
    • Instant Hotspot to automatically use your cellular connection to get online with your other devices
    • AirDrop compatibility with OS X Yosemite
    • Available on iPhone 5 or later, iPad (4th generation), iPad Air, iPad mini, and iPod touch (5th generation)

    Spotlight improvements

    • Displays suggestions from Wikipedia entries, places nearby, movies (US only), popular web sites, App Store, iTunes Store and iBooks Store
    • Safari also supports Spotlight suggestions alongside Top Hit and search suggestions
    • Supported for local languages in US, UK, Austria, Australia, Belgium, Canada, France, Germany, Italy, Japan, Netherlands, Spain, Switzerland

    Mail improvements

    • Easily jump between drafts and your inbox with a simple swipe down on the draft
    • Intelligent suggestions for Calendar events and Contacts
    • VIP threads

    Siri improvements

    • Improvements to responsiveness, reliability and accuracy
    • “Hey, Siri” option to initiate Siri using just your voice when your device is plugged in
    • Streaming voice recognition
    • Works with Shazam to answer “What song is playing?”
    • Purchase content from iTunes Store
    • Safari improvements
    • DuckDuckGo search engine support
    • Private browsing per tab
    • Subscribe to RSS feeds in Shared Links
    • Use Camera to scan and enter credit card info

    Maps improvements

    • Flyover city tours
    • Maps place cards in Phone and Contacts
    • Inline map view and travel time notifications for Calendar events

    App Store improvements

    • New Explore tab for easier category browsing
    • Top trending searches displayed in Search tab
    • Scrolling search results
    • App video previews
    • Editors’ Choice badges
    • Quick access to key contacts in multitasking view
    • Interactive Notifications for Messages, Mail, Calendar, Reminders and enabled third-party apps
    • New Tips app to help you do more with your iOS devices
    • iBooks app built into iOS, now with auto night mode and new organization for book series
    • Podcasts app built into iOS
    • Battery usage by app
    • iCloud Keychain can use saved website passwords to easily sign in to associated apps
    • FaceTime Audio call waiting
    • Rich text editing in Notes
    • Peer-to-peer AirPlay discovery and playback

     Enterprise features

    • Expanded data protection to Calendar, Contacts, Messages, Reminders, and Notes in addition to Mail and 3rd-party apps
    • Per message S/MIME email controls
    • Improved UI to make it easier for users to understand the remote management of their device
    • Automatic reply for Exchange
    • Free/busy lookup for Calendar invitations
    • MDM Managed books can be automatically pushed to users

    Accessibility features

    • Redesigned Zoom with one-handed control and multiple zoom modes including picture-in-picture
    • Built-in timer and Touch ID support for Guided Access
    • Speak Screen to read out contents of the screen via gesture or Siri command
    • VoiceOver improvements including Alex voice option and Braille input support
    • Multi-device support for MFi hearing aids to seamlessly switch from one paired iOS device to another

    Features for China

    • Vector-based maps
    • Turn-by-turn navigation
    • Lunar calendar support
    • Improved predictive input
    • Improved weather data

    Expanded language support

    • Dictation support for 22 additional languages: Croatian, Catalan, Czech, Danish, Dutch, Finnish, Greek, Hungarian, Indonesian, Malay, Norwegian, Polish, Portuguese (Brazil), Portuguese (Portugal), Romanian, Russian, Slovakian, Swedish, Thai, Turkish, Ukrainian, Vietnamese
    • New keyboards for English (India), Bengali, Filipino, Marathi, Slovenian, and Urdu
    • Hindi localization
    • Definitions of a selected word for additional languages: Russian, Portuguese (Brazil), Thai, Turkish
    • Spanish-English bilingual dictionary
    • Spell check for Turkish
    • Hebrew language support for Text to Speech and VoiceOver

    New developer capabilities including

    • Extensibility, giving apps new sharing options and the ability to create widgets, photo filters and editing tools in Photos, and 3rd-party keyboards
    • Metal, a new graphics technology for game providers to bring console-class 3D games to mobile devices
    • SpriteKit and SceneKit for improved 2D and 3D games
    • HealthKit, so health and fitness apps can share their data with each other
    • HomeKit, a new way for you to control supported devices in your home using Siri
    • Touch ID support so you can sign in to third-party apps with just your fingerprint
    • CloudKit, offering a complete and scaleable back-end solution helping developers eliminate the need for writing server code and maintaining servers

    Bug fixes

    Some features may not be available for all countries or all areas.
    For information on the security content of this update, please visit this website:

    http://support.apple.com/kb/HT1222

    Screen Shot 2014-09-18 at 11.29.20

    Happy Coding!

     
  • Jay Versluis 5:46 pm on September 13, 2014 Permalink | Reply
    Tags: ,   

    How to test which class presented a UIViewController 

    The NSObject class has an interesting method called isKindOfClass. As the name suggests it lets you test what kind of class it belongs to. As everything we use inherits from NSObject, this method is available in our own classes we use in iOS and Mac development.

    This method can come in handy for example when three different classes present the same view controller and you’d like to make decisions based on which controller has presented your content. Consider the following two example.

    If you present a UIViewController via a modal segue you can test which class the presenting view controller belonged to like so:

    // grab a reference to the presenting view controller 
    id thePresenter = self.presentingViewController;
    
    // and test its class
    if ([thePresenter isKindOfClass:[YourViewController class]]) {
        // do this
    } else {
        // do that
    }
    

    If however your view controller was presented via a UINavigationController then the above isn’t going to work. Instead you need to check which view controller was on the navigation stack previously.

    Here’s how to do this:

    // grab a reference to the previous view controller 
    id thePresenter = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count - 2];
    
    // and test its class
    if ([thePresenter isKindOfClass:[YourViewController class]]) {
        // do this
    } else {
        // do that
    }
    

    Happy Coding!

     
  • Jay Versluis 4:48 pm on September 3, 2014 Permalink | Reply
    Tags: UIPasteboard   

    How to access values from the iOS Clipboard (from copy and cut operations) 

    Screen Shot 2014-09-03 at 16.39.32iOS has a class called UIPasteboard which lets you access the last value that a user has copied or cut to the clipboard (or pasteboard).

    The class has a singleton which lets you access a string like so:

    // latest copy/cut string operation
    NSString *latest = [UIPasteboard generalPasteboard].string;
    

    This will work fine when any kind of text is involved. Copy/Cut/Paste is also available for images from the Photos app though, and you can access the latest UIImage like this:

    // latest image
    UIImage *latestImage = [UIPasteboard generalPasteboard].image;
    

    Note that those two values are mutually exclusive: if you’ve copied an image, then the text string will be nil, and when you’ve copied text then the image value will be nil.

    The UIPasteboard class is very versatile and lets you do all kinds of things – check out the Class Reference for more information:

    Happy Coding!

     
  • Jay Versluis 12:37 pm on September 2, 2014 Permalink | Reply
    Tags: WordPress   

    How to add ordered image uploads in WordPress for iOS 4.0.3 

    AppIcon76x76@2xI’ve finally figured out how to tweak WordPress for iOS so that images are uploaded in the correct order. I had been working on this fix for so long that the project has now changed and the file in question is no longer called in the current version of WordPress for iOS (4.1.3 at the time of writing).

    The team are already working on a much better solution for inserting images, but until then the following works fine for me. Perhaps it’ll come in handy for future projects.

    Before version 4.1.x, image uploads happened in a file called WPMediaUploader.m (found in Classes/Controllers/Media). In its uploadMediaObjects method, a for/in loop sends each object to an upload routine which inserts the relevant code into the post editor via a notification.

    The trouble was that all uploads happen concurrently and hence the upload that finished first is inserted, neglecting the order in which the images were picked. Here’s the original method:

    - (void)uploadMediaObjects:(NSArray *)mediaObjects
    {
        if ([mediaObjects count] == 0)
            return;
        
        self.isUploadingMedia = YES;
        
        _numberOfImagesToUpload += [mediaObjects count];
        for (Media *media in mediaObjects) {
            [self uploadMedia:media];
        }
    }
    

    I tried a LOT to fix this, and the solution that works best is to wait for the first upload to finish and only then submit the next object to the upload queue. Here’s how I did this.

    First I’ve added two new properties to the class: one holding the current array of media objects, and an int to count which object is currently uploading:

    @property int currentUpload;
    @property (nonatomic, strong) NSArray *mediaToUpload;
    

    In the uploadMediaObjects method I’m storing this array in my property and start the first upload. I’m also incrementing the counter so we can keep track of all uploads in another method:

    - (void)uploadMediaObjects:(NSArray *)mediaObjects
    {
        if ([mediaObjects count] == 0)
            return;
        
        _numberOfImagesToUpload += [mediaObjects count];
        
        self.isUploadingMedia = YES;
        
        // store reference to media array
        self.mediaToUpload = mediaObjects;
        
        // observer for next media
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(uploadNext) name:@"UploadTheNextMediaThing" object:nil];
        
        // upload first object and increment counter
        [self uploadMedia:mediaObjects.firstObject];
        self.currentUpload++;
    
    }
    

    We also need a method that can be called via a notification when the current upload has finished:

    - (void)uploadNext {
        
        // called via observer when current upload has finished
        
        // is another upload required?
        if (self.currentUpload < self.mediaToUpload.count) {
            
            Media *nextMedia = [self.mediaToUpload objectAtIndex:self.currentUpload];
            [self uploadMedia:nextMedia];
            self.currentUpload++;
        
        } else {
            [self cleanup];
        }
    }
    

    If another upload is required we’ll submit it, incrementing the counter. If not, we’ll reset those properties via a cleanup routine (more on that in a moment).

    The observer that we’ve setup will be called after an upload, no matter if successful or not. For clarity I’ve added it twice (but of course it’s enough to add it once at the end of the method):

    - (void)uploadMedia:(Media *)media
    {
        [self uploadMedia:media withSuccess:^{
            if ([media isDeleted]) {
                DDLogWarn(@"Media uploader found deleted media while uploading (%@)", media);
                return;
            }
            [[NSNotificationCenter defaultCenter] postNotificationName:MediaShouldInsertBelowNotification object:media];
            [media save];
            NSLog(@"I've finished uploading image: %@", media.filename);
            
            // post notification that we're done uploading
            NSNotification *notification = [NSNotification notificationWithName:@"UploadTheNextMediaThing" object:self];
            [[NSNotificationCenter defaultCenter]postNotification:notification];
            
            
        } failure:^(NSError *error){
            if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) {
                DDLogWarn(@"Media uploader failed with cancelled upload: %@", error.localizedDescription);
                return;
            }
            
            [WPError showAlertWithTitle:NSLocalizedString(@"Upload failed", nil) message:error.localizedDescription];
            
            // post notification that we're done uploading
            NSNotification *notification = [NSNotification notificationWithName:@"UploadTheNextMediaThing" object:self];
            [[NSNotificationCenter defaultCenter]postNotification:notification];
            
        }];
    
    }
    

    While I was testing this I’ve noticed that this class isn’t initialised again when you start another post, so our properties still contain (the wrong) values on our next post. Hence we need to do a bit of cleanup when we’re done by removing the observer and resetting our properties:

    - (void)cleanup {
        
        // remove observer
        [[NSNotificationCenter defaultCenter]removeObserver:self name:@"UploadTheNextMediaThing" object:nil];
        
        // reset counter and media array
        self.currentUpload = nil;
        self.mediaToUpload = nil;
        
    }
    

    In case someone hits cancel during our uploads we must make sure we also call the above, otherwise we’ll experience another crash when we write the next post:

    - (void)cancelAllUploads
    {
        for (Media *media in _mediaUploads) {
            NSDictionary *uploadInformation = [_mediaUploads objectForKey:media];
            AFHTTPRequestOperation *operation = [uploadInformation objectForKey:WPMediaUploaderUploadOperation];
            [operation cancel];
        }
        [_mediaUploads removeAllObjects];
        self.isUploadingMedia = NO;
        [self cleanup];
    }
    

    And that’s it! I’ve created a fork the project with the above changes:

    The “real” WordPress project is also on GitHub, fork away:

    After WordPress 4.1 the project has been split into smaller chunks which will make it easier to integrate parts of WordPress into our own apps soon. See what else is available:

    Happy Coding!

     
  • Jay Versluis 5:32 pm on August 9, 2014 Permalink | Reply
    Tags: Pinterest, ,   

    How to open the Pinterest App from your own iOS App 

    Pinterest_Badge_RedYou can open Pinterest links from your iOS app directly in the Pinterest app if it’s installed. This includes direct links to a user, a user’s board, or a specific pin.

    In the following code snippets we’ll do just that, and if the Pinterest App is not installed on the device we’ll open the link in Safari instead. These methods can be hooked up to a UIButton.

    Note that for this to work, users need to be logged in to the Pinterest App – otherwise the app opens with a login prompt and not the link we want.

    Opening a Pinterest User Profile

    Much like on Twitter, users on Pinterest have handles. Mine is versluis2000, and my Pinterest URL is http://www.pinterest.com/versluis2000. Here’s how you open this user via the Pinterest app:

    - (IBAction)openPinterestUser:(id)sender {
        
        // open the Pinterest App if available
        if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"pinterest://user/juliav1"]]) {
            
            // opening the app didn't work - let's open Safari
            if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.pinterest.com/versluis2000/"]]) {
                
                // nothing works - perhaps we're not online
                NSLog(@"Dang!");
            }
        }
    }
    

    Trying to display your own Pinterest User Profile may crash the Pinterest App – at least that’s what happened in my tests.

    Opening a Pinterest Board

    Users on Pinterest can pin links to their boards which work like collections or categories. Those boards have slugs that appear after the user handle. I have a board called iOS Projects which has the following URL: http://www.pinterest.com/versluis2000/ios-projects/

    Here’s how we can open one directly in the Pinterest App:

    - (IBAction)openPinterestBoard:(id)sender {
        
        // open the Pinterest App if available
        if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"pinterest://board/versluis2000/ios-projects"]]) {
            
            // opening the app didn't work - let's open Safari
            if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.pinterest.com/versluis2000/ios-projects/"]]) {
                
                // nothing works - perhaps we're not online
                NSLog(@"Dang!");
            }
        }
    }
    

    Opening a Pinterest Pin

    When a user finds a link on the web and pins it, the link will receive a unique numeric ID. Such an ID is independent from the user who pins it. Here’s a pin to a sketch of a Polaroid camera I drew: http://www.pinterest.com/pin/76279787413881109/

    Let’s open this pin in the Pinterest App:

    - (IBAction)openPinterestPin:(id)sender {
        
        // open the Pinterest App if available
        if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"pinterest://pin/76279787413881109"]]) {
            
            // opening the app didn't work - let's open Safari
            if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.pinterest.com/pin/76279787413881109/"]]) {
                
                // nothing works - perhaps we're not online
                NSLog(@"Dang!");
            }
        }
    }
    

    How about pinning something directly from my own app?

    If you’d like users to pin something directly from your app, take a look at the iOS Pin It SDK – brought to you by the friendly folks at Pinterest. The article also explains the deep linking structure we’re using in the above examples:

    Care for a Demo Project? https://github.com/versluis/Pinterest

    Happy Coding!

     
  • Jay Versluis 3:57 pm on August 3, 2014 Permalink | Reply
    Tags: , ,   

    Creating Multiple In-App Purchases in iOS 

    In this screencast I’ll show you how to create multiple in-app purchases in you iOS app. The first part is a quick overview, and the second part shows how I’m tinkering with the code (members only).

    This is based on an earlier tutorial in which I’m explaining how to create a single in-app purchase – if you’d like to follow along, you can find it here:

    In a nutshell we’ll duplicate the earlier Shop class, add our new product identifier and amend the StoreKit observer method, as well as the alertView so that it can unlock the correct product.

    The source code for this project is available on GitHub: the master branch is the earlier tutorial with a single product, and the Multi-IAP branch is what’s shown in this video.

    This content is for members only.

    Happy Coding!

     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel
Password Reset
Please enter your e-mail address. You will receive a new password via e-mail.