PHP Max Upload Size – Dreamhost

I’ll preface this post by stating that I don’t endorse Dreamhost and don’t particularly care for it as a service, however, I work with several sites that are hosted there.

That being said, previously when I needed to change the maximum upload size that PHP would allow, I’d simply run the dh-phpini script and modify the ini file to match my desired upload size. The last time I tried using this, it did not work successfully so if you’re having trouble with that, here’s a work around. Note: the goal of this post is to change the following PHP variables in the ini file:

POST_MAX_SIZE and UPLOAD_MAX_FILESIZE

If you’ve got a better way, please feel free to leave a comment. Also, it’s worth noting Dreamhost doesn’t support (although they do allow) this type of modification and won’t help you if you mess things up… I’m not responsible either :-)

To get started, you’re going to need to have access to a shell account on the server. You can set this up under ‘Manage Users’ from the Dreamhost panel).

Step 1:

SSH into the server like so:

ssh username@domainname.com

You’ll possibly be prompted to verify that you would indeed like to connect to this unknown server. If you choose to accept, you’ll then be prompted for your password. Go ahead and put that in.

Next, assuming your ssh account’s home directory is the home directory for the account, you’ll need to make a directory called ‘.php’ and inside of that directory we want a folder named ’5.3′, you can do that like this:

mkdir -p .php/5.3

This brings up an important point. For this configuration to work, you’ll need to be running PHP 5.3 on that domain. You can change this under the ‘Manage Domains’ section of the Dreamhost panel.

Next we’ll want to cd into our newly made directory:

cd .php/5.3

Next we want to copy the “generic” or default php.ini into our new directory:

cp /etc/php53/php.ini $HOME/.php/5.3/php.ini

We’ll use the nano text editor to edit the file:

nano php.ini

Next, you’ll want to find the POST_MAX_SIZE and UPLOAD_MAX_FILESIZE and edit those values.

Now Press Control + X and Save.

We now need to restart PHP:

killall -9 php53.cgi

If all went as planned, your max upload size should now be changed.

[Rails] Heroku Image Attachments Using Paperclip and S3

Intro

Heroku is awesome, it makes deployment easy and is an all around great service. However, it does have a few limitations and one of those is the inability to upload files. When we need to do this, we use thoughtbot’s paperclip gem which makes managing file attachments easy coupled with Amazon’s S3 (simple storage service).

Amazon S3

S3, simply put, is cloud storage provided by Amazon. Although it does have a free tier there is a price associated with using S3. As of this writing, the free tier gives you 20,000 GET requests, 2,000 PUT requests and 15gb of data transfer out per month. You can view all of the pricing tiers and information at Amazon’s S3 Pricing Page. To get an estimate of your cost you can head over to Amazon’s cost estimator and clicking “Amazon S3″ on the left. To get started, you’ll need to sign up (note: all sign-ups require a credit card including the free tier). Once you’re in you’ll need to go to your security credentials page under “My Account / Console”:

Once you’re on the security credentials page, you’ll need to scroll down to the “Access Credentials” section and by default you should be on the “Access Keys” tab:

You need to make note of the Access Key ID and then click the “Show” link for your Secret Access Key. Copy these and hang on to them, we’ll need them in just a few minutes. Next we’ll need to create a “Bucket” which for our purposes is similar to a folder. There are several ways you can go about doing this. To create a bucket we’ll use the S3 AWS management console provided by Amazon. In the upper left corner you’ll see the “Create Bucket” button:

Click it. You’ll see a screen like this:

Name your bucket whatever you’d like and select the appropriate region. I’m going to use “US Standard” because… I’m in the US. Then hit the “Create” button. Congratulations, you just created your first bucket. Now let’s code.

Code

You should start by installing the paperclip and S3 gems (we need a gem to communicate back and forth with S3), in your gemfile:

gem 'paperclip'
gem 'aws-s3'

Go ahead and bundle install

Next, much like you have a database.yml in your config folder, you need to create an s3.yml that the S3 gem will use to reference your S3 credentials. The contents of the file should look like this:

access_key_id:      
secret_access_key:  
bucket:             

You should fill this out accordingly based on the information you got from the Security Credentials section of the S3 site and whatever you named your bucket. Update it and save.

Next, we need to update our model to include an attached file. For this tutorial, I’m going to attach an image to a model called User and I’m going to call it Avatar. So here’s what we need to do in the console:

rails generate migration add_avatar_to_users avatar_file_name:string avatar_content_type:string avatar_file_size:integer avatar_updated_at:datetime

Go ahead and run rake db:migrate. So we’re adding 4 properties to our user model: avatar_file_name, avatar_content_type, avatar_file_size, avatar_updated_at. All of these should be self explanatory in case it’s not clear, the content_type property will store information like jpeg, png, etc.

Let’s head over to the model (for me user.rb) and let it know of this new attachment:


has_attached_file :avatar,
  :styles =>{
    :thumb  => "50x50",
    :medium => "400x400"
  },
  :storage => :s3,
  :s3_credentials => "#{Rails.root}/config/s3.yml"",
  :path => ":attachment/:id/:style.:extension",
  :bucket => "the_bucket_name"

On lines 2-5 we’re telling paperclip we want 2 styles of our uploaded image (you can change this to allow for more styles with different sizes). It’ll resize them for us an store 3 copies, the thumb, medium-sized, and the original uploaded image. Just to be clear, it WILL resize these images for us (using ImageMagick). On line 6 we’re identifying the fact that we’d like to use S3 to store this avatar and then on line 7 we define our configuration file’s location. On line 8 we are defining our directory structure for storage on S3. Let’s say you’re a user with the id of 5. If you upload your jpeg avatar, it’ll be stored inside the bucket we specified with the following path: avatar/5/medium.jpg. On line 9 we use the same bucket we created previously.

Now we need to update our views to handle the new avatar. We’ll start with our form to create users (or edit users):

<%= form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %>
  <%= form.file_field :avatar %>
<% end %>

This is pretty straightforward, just make sure you’re making the form multipart (to allow for the file upload) and then adding the file field for the avatar. To display this avatar you do the following:

<%= image_tag @user.avatar.url(:thumb) %>

You can, of course, change :thumb to be :medium or whatever style you’ve predefined in the model. For additional reference or to see the other cool things you can do with paperclip, head over here.

Scanning a Bar Code with ZBarSDK

We’re going to focus on scanning UPCs, however I believe the ZBarSDK can be used to scan QRCodes and that may be the topic of another tutorial at a later date (feel free to leave a comment or tweet at me if you would be interested). You can download the sample project here.

To get started I’m going to create a new project and use the Single View template. We’ll need to add a few frameworks to our project:

AVFoundation.framework
CoreMedia.framework
CoreVideo.framework
QuartzCore.framework
libiconv.dylib

You’ll need to download the ZBarSDK from here: http://zbar.sourceforge.net/iphone/ (you’ll need to scroll about halfway down to the section titled “iPhone Developers”. Once you’ve downloaded the DMG file it’s pretty straightforward about how to get the library into your project:

Go ahead and drag the ZBarSDK folder into your XCode project.

In our ViewController’s header we need to import the ZBarSDK header file:
#import "ZBarSDK.h"

Let’s also make our ViewController a ZBarReaderDelegate:
@interface ViewController : UIViewController

While we’re in the header let’s go ahead and declare an IBOutlet for a UIButton named “scanButton”:

IBOutlet UIButton *scanButton;

@property (nonatomic, retain) IBOutlet UIButton *scanButton;

Also be sure to @synthesize:

@synthesize scanButton;

Next we’ll create an IBAction for the scanButton called scanButtonPress:

-(IBAction) scanButtonPress:sender;

Your ViewController’s header should now look like this:


#import <UIKit/UIKit.h>
#import "ZBarSDK.h"

@interface ViewController : UIViewController <ZBarReaderDelegate> {
    IBOutlet UIButton *scanButton;
    
}

@property (nonatomic, retain) IBOutlet UIButton *scanButton;

-(IBAction) scanButtonPress:sender;

@end

Go ahead and create a button in Interface Builder and link it to the outlet and action we’ve created:

Next let’s work on the scanButtonPress action:

-(IBAction)scannerPress:(id)sender{
    
    ZBarReaderViewController *reader = [ZBarReaderViewController new];
    reader.readerDelegate = self;
    
    [reader.scanner setSymbology: ZBAR_UPCA config: ZBAR_CFG_ENABLE to: 0];
    reader.readerView.zoom = 1.0;
    
    [self presentModalViewController: reader
                            animated: YES];
    
}

We’ll go through line by line:

On line 3, we create a new ZBarReaderViewController and on line 4, set our ViewController as the delegate. On line 6-7, we set up the reader and tell it we’re going to be scanning a UPC (ZBAR_UPCA, you can read about the supported symbologies here) and we want the zoom level to be 1.0. Finally, on line 9, we show the reader. If you’ve ever used the UIImagePickerController. This will begin to seem familiar.

Now we need to setup our delegate method — this is pretty vanilla code from the SDK documentation:

- (void) imagePickerController: (UIImagePickerController*) reader
 didFinishPickingMediaWithInfo: (NSDictionary*) info
{
    id<NSFastEnumeration> results = [info objectForKey: ZBarReaderControllerResults];
    
    ZBarSymbol *symbol = nil;
    
    for(symbol in results){
           
        NSString *upcString = symbol.data;
        
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Scanned UPC" message:[NSString stringWithFormat:@"The UPC read was: %@", upcString] delegate:self cancelButtonTitle:nil otherButtonTitles:@"Ok", nil];
        
        [alert show];
        
        [reader dismissModalViewControllerAnimated: YES];
        
    }
    
    
}

Basically the Picker can return multiple results, so we’ll enumerate through those (lines 4-8 — also the for loop). On line 10 we actually pull the UPC result from the data returned from the Picker (ZBarReaderViewController) and then on lines 12 and 14 we display that UPC with an alert and dismiss the ZBarReaderViewController modal on line 16.

Again, this is very vanilla information available to you in the official SDK documentation, which is available here, where you’ll also find additional information about the ZBarSDK.

It’s important to note that because the reader uses the camera you will have to run this on an actual device (not the simulator) to test it.

[Rails] Devise and Active Admin Single User Model

If you’re working on a project that requires an Admin section and you already require authentication for other areas you should really consider using Active Admin with Devise. By default Active Admin uses Devise for it’s authentication but creates a new user model specific to admins. If you already have a user model in place or would like to simply have one user model, there’s not much to it.

To get started, you’ll need to add a few gems to your gem file (if using > Rails 3.1, this assumes you already have sass-rails in your gem file.

Gemfile:

gem 'devise'
gem 'activeadmin'
gem 'meta_search',    '>= 1.1.0.pre'

Go ahead and run bundle install to get those gems installed. We’ll start by configuring Devise. We’re going to create a user model named …wait for it… "User" (unique, I know). If you’ve never used Devise before and want more information, you can check out their readme here. To get going we’re going to run a few generators:

rails generate devise:install

Which generates our Devise installation. Followed by:

rails generate devise User

That generates our user model. Before we rake our user migrations, let’s add a boolean admin flag to the user model:

rails generate migration add_admin_flag_to_users admin:bool

Go ahead and run your migrations:

rake db:migrate

Now, let’s go ahead and install Active Admin — normally, if you’re following the Active Admin docs (available here) you’d run the following command:

rails generate active_admin:install

However, this generates it’s own user model (called AdminUser) that we don’t want. Instead, we’ll run the following command:

rails generate active_admin:install --skip-users

This basically tells Active Admin not to make it’s own model. If you look inside the Active Admin initializer there are, amongst other things, two methods that it uses to a) make sure the user is an admin (config.authentication_method = :authenticate_admin_user!) and b) return the admin user (config.current_user_method = :current_admin_user). Because we’re using our own model we need to define these methods and we’ll do so in the application_controller.rb:

  def authenticate_admin_user!
    authenticate_user! 
    unless current_user.admin?
      flash[:alert] = "This area is restricted to administrators only."
      redirect_to root_path 
    end
  end
  
  def current_admin_user
    return nil if user_signed_in? && !current_user.admin?
    current_user
  end

Now if you have a user that has the admin flag set to TRUE, they’ll be able to browse to /admin and view the Active Admin panel. If they’re not logged in, they’ll be prompted to do so, if they’re not an admin they’ll be redirected to the root path with a flash message informing them of the restricted area.

Twitter on iOS: Access Twitter Accounts

Although it’s been around for roughly a year now, I feel I’ve witnessed a little bit of magic each time I see the following dialog:

“Would like Access to Twitter Accounts”

Prior to the integration of Twitter into iOS 5 integrating Twitter was a real mess with a variety of 3rd-party solutions. We’re going to take a look at how to access a user’s Twitter account which can then be used for single sign on, tweets, etc. If you need additional references, the Apple documentation is available here.

To get started, add the Accounts framework as well as the Twitter framework to your project:

Now include Accounts.h, the accounts header as well as Twitter.h in your header:

#import <Accounts/Accounts.h>
#import <Twitter/Twitter.h>

We need to create a few instance variables (I made the account store an instance variable here due to an error I was getting when making a TWRequest, you can read about this error on Stack Overflow):


 NSArray *theAccounts;
 ACAccountStore *accountStore;

I’ll be adding the following code to my viewDidLoad method, however, you could associate it with a button action or somewhere throughout a registration process — where ever you see fit.


    self.theAccounts = [[NSArray alloc] init];
    
    self.accountStore = [[ACAccountStore alloc] init];
    
    ACAccountType *twitterAccount =
    [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
    
    [self.accountStore requestAccessToAccountsWithType: twitterAccount withCompletionHandler: ^(BOOL allowed, NSError *error) {
        if(allowed) {
            self.theAccounts = [accountStore accountsWithAccountType: twitterAccount];
            NSLog(@"theAccounts: %@", self.theAccounts);
        }
        else{
            //handle error gracefully
             NSLog(@"Declined or error");
             
         }
    }];
    

Let’s go through this line-by-line. On line 1 we initialize our accounts NSArray. On line 2 we create an ACAccountStore object. This object allows us to access and store accounts. On line 5 we define an account type which we’ll use in line 7 to tell the account store we want to access Twitter accounts specifically. It’s worth noting that the accounts framework currently only supports Twitter accounts but is likely to be expanded in the future. In addition to specifying the account type, in line 7 we also make the request to access the accounts. It’s at this point that iOS will prompt the user for approval. We’ll check to make sure (on line 9) that it’s allowed and proceed to assign those accounts to an NSArray on line 10. Line 11 is simply for debugging purposes and logs the account output. On lines 13-17 you will want to handle a rejection by the user or an error.

Now that we have access to the accounts, we can interact with the Twitter API (documented here) using the Twitter framework also available in the iOS SDK. The core of this functionality is centered around the TWRequest.

We’re going to make a simple request to pull the timeline of the first account we gained access to.


    TWRequest *twRequest = [[TWRequest alloc]
                              initWithURL:
                              [NSURL URLWithString:@"https://api.twitter.com/1/statuses/user_timeline.json"]
                              parameters:nil
                              requestMethod:TWRequestMethodGET];
    
    ACAccount *theAccount = [self.theAccounts objectAtIndex:0];
    
    [twRequest setAccount:theAccount];
    [twRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) { 
        if ([urlResponse statusCode] == 200) {
            NSError *jsonError = nil;
            NSDictionary *feed = [NSJSONSerialization JSONObjectWithData:responseData
                                                            options:0
                                                              error:&jsonError];
            NSLog(@"User's feed: %@", feed);
        }
    }];

On line 1 we setup the request. Again, you can change the Twitter API URL based on the action you’d like to take. On lines 7 and 9 we specify we’d like to use the first account we retrieved earlier. On lines 10-18 we execute the request and parse the JSON. You could then place this in a UITableView or use the data however your application requires.

That’s it for this quick run through of using the Accounts and Twitter frameworks.

Twitter on iOS: Tweeting a Tweet, The TweetSheet

Tweeting on iOS hasn’t been easier since iOS 5.

To get started, add the Twitter.framework to your project:





Next, import Twitter.h into your ViewController:

#import <Twitter/Twitter.h>


You’ll probably want to create a new action on a UIButton, so we’ll call that tweetButtonPress:


- (void) tweetButtonPress:sender {
    
}

Inside that method we’ll create a TWTweetComposeViewController, this is what is referred to as the “TweetSheet” and looks something like this:

if([TWTweetComposeViewController canSendTweet]){
//Create the tweetsheet
    TWTweetComposeViewController *tweetSheet = [[TWTweetComposeViewController alloc] init];

//Set initial text of the tweet
[tweetSheet setInitialText: @"Hello Twitter World"];

//Add a completion handler for the tweetsheet
    tweetSheet.completionHandler = ^(TWTweetComposeViewControllerResult result){
        [self dismissModalViewControllerAnimated:YES];
    };

//Show the tweetsheet
[self presentModalViewController:tweetSheet animated:YES];
}

else{
 NSLog(@"Handle inability to send Tweet");
}

Most of this is pretty straightforward but on line 6 we set the initial text of the Tweet. This will be user editable but you can certainly have a “recommended tweet”. On line 1 we check to see that the user can even send a Tweet. There are a few reasons they might not be able to: they may not have a Twitter account setup on their device or they may not currently have an internet connection — you can handle these issues however you please in the else starting on line 17. On lines 9-11 we setup a completion handler that will dismiss the TweetSheet when the user is done. Finally, on line 14 we bring the TweetSheet into the view.

Now, there are a few additional methods you can call to attach images and links to the user’s tweets.

To add a URL to the Tweet:

[tweetSheet addURL:[NSURL URLWithString:@"http://jaysonlane.net"]];

Twitter will automatically shorten this to a t.co link.

To add an image to the Tweet:

[tweetSheet addImage:[UIImage imageNamed:@"image.png"]];

And Twitter will handle the uploading for you. These types of attachments will be displayed on the right side of the TweetSheet held on by the paperclip to let the user know they’ve been added.

Post-Release Development Bundle Identifiers and Display Names

So you’ve released version 1.0 and it’s in the App Store but you’ve noticed a few bugs and there are still those features you were holding out until 1.0.1. You tweak some code and test on your device but now you’ve lost the current release version because they both have the same bundle identifier. Sometimes …most of the time, as a developer it’s important for you to have both the current release version AND the current beta version on your device. Project’s aren’t configured like this out of the box but it is certainly possible to make this happen without manually changing the bundle identifier every time by way of User Defined Build Settings and variables.

If you take a look at your Application’s plist, you’ll see your bundle name, and bundle identifier along with other information about your app. You’ve probably seen a few fields that include variables that look like this: ${PRODUCT_NAME} or ${EXECUTABLE_NAME}. We’re going to use that system to change the bundle identifier and the bundle display name dependent on the build-type (Debug, Release, Ad Hoc, etc).

To get started, open up your Application Target and click the Build Settings tab:

Once you have this open, click the “Add Build Setting” button in the lower right corner:

Then click “Add User-Defined Setting”. You’ll see XCode adds a section named “User-Defined” and a new setting for you to type in. Type in BUNDLE_DISPLAY_NAME_SUFFIX and hit enter. We’re going to use this as a string to append to our bundle display name (the name of the app that shows on the springboard). Now you should see this:

You can enter in whatever value you like for debug, a few common or recommended ones are “Beta”, “B”, ß but you can use whatever you want. Don’t enter a value in for release as we don’t want to append anything when we build for release as that build should be headed for the app store.

Next, let’s add another User Defined Setting and called this one BUNDLE_IDENTIFIER_SUFFIX. For this you can, again, enter any value you like for Debug. This is appended to the bundle identifier and since an iOS requires unique bundle identifiers this beta version of the app needs one different than the release version. I usually use ‘.dev’ for this field but you could use something like ‘.beta’ or whatever you’d like. So now your settings should look similar to this:

Now that we have the variables set let’s go to the application’s plist and use them. In the bundle display name field simply append ${BUNDLE_DISPLAY_NAME_SUFFIX} to whatever is already there. Move on to the Bundle identifier field and add ${BUNDLE_IDENTIFIER_SUFFIX} and append that to the existing data there. When complete, you’ll see something like this:

Now you’re set. When you build for Debug releases your app will be named with your appended string as well as your bundle identifier. You’ll be able to keep the current release from the app store installed as well as your development build build XCode or TestFlight!

Lock screen “Now Playing” with MPNowPlayingInfoCenter

Note: Example project is available here

One of the great additions iOS 5 brought us is the ability to display meta data about currently playing tracks on the lock screen. This is a great convenience to users and a must if your app has background audio playing. I know I use this to great extent, especially when driving. Best of all, it’s actually quite simple to get going.

For the sake of this tutorial, we’re going to be focusing mainly on the MPNowPlayingInfoCenter and not much on how to play streaming audio. If you have questions, as always, please feel free to leave a comment. I, as I’ve stated in the past, am still fairly new to the iOS/Objective-C world so if you see something that makes you say ‘UR DOING IT WRONG!’, please let me know. If you’d like to review the details of MPNowPlayingInfoCenter, you can read the Apple documentation.

To get started, create a new project. I created one using the single view template but feel free to do whatever you’d like. Once you’ve created the project there are a few things we need to do to get the project setup. By default, simply playing audio won’t persist if the application leaves the foreground. We need to tell iOS we’d like to play background audio. To get started doing this, open up your application’s info.plist file and add a new row: “Required background modes” (UIBackgroundModes). This creates an array with Item 0 change the value to “App plays audio” (audio). I’ve got a screen shot of what this should look like:

Next, there are a few frameworks we need to link to our project:

  1. AVFoundation.framework
  2. MediaPlayer.framework
You can do this by click on your project, and selecting the Target and swiveling down “Link Binary with Libraries”, click the + at the bottom and begin typing those names. Once you’re done, it should look like this:
Now we’re ready to start playing audio. In my view controller, I’ve created a simple IBOutlet UIButton called playButton and linked it in the nib. I’ve also attached an IBAction, playButtonPress to the button’s touch up inside event.

You can see those items in myViewController.h:


@interface ViewController : UIViewController {

IBOutlet UIButton *playButton;

}

@property (nonatomic, retain) IBOutlet UIButton *playButton;

-(IBAction)playButtonPress:(id)sender;

Next I’m going to import the MPMoviePlayerController header to add a player to my view controller class:

#import <MediaPlayer/MPMoviePlayerController.h>

To add the player controller we’ll add these lines to the ViewController.h:

MPMoviePlayerController *audioPlayer;

and

@property (nonatomic, retain) MPMoviePlayerController *audioPlayer;

Swing over to your ViewController.m file and we’re going to add a few more headers:

#import <MediaPlayer/MPNowPlayingInfoCenter.h>
#import <MediaPlayer/MPMediaItem.h>
#import <AVFoundation/AVFoundation.h>

And we’ll synthesize our playButton and audioPlayer:

@synthesize playButton, audioPlayer;

In viewDidLoad we’ll initialize our audio session and audioPlayer and pre-load it with content from the web. We’re going to use Oliver Drobnik’s Cocoanetics podcast as our audio feed for this tutorial. Oliver has an awesome podcast packed with great info for iOS developers, you can find out more about it at http://cocoanetics.com.


[[AVAudioSession sharedInstance] setDelegate: self];

NSError *myErr;

// Initialize the AVAudioSession here.
if (![[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&myErr]) {
    // Handle the error here.
    NSLog(@"Audio Session error %@, %@", myErr, [myErr userInfo]);
}
else{
    // Since there were no errors initializing the session, we'll allow begin receiving remote control events
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}

    //initialize our audio player
    audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:@"http://www.cocoanetics.com/files/Cocoanetics_031.mp3"]];
    
    [audioPlayer setShouldAutoplay:NO];
    [audioPlayer setControlStyle: MPMovieControlStyleEmbedded];
    audioPlayer.view.hidden = YES;
    
    [audioPlayer prepareToPlay];

It’s important we have line 12 as this is what tells iOS we want to receive any remote control events from the lock screen (i.e. backward, play, pause, forward). I’ve found that without that line your information will never display (here’s a link to my Stack Overflow question chronicling my journey to that discovery).

Moving onward, next we need to create our action that actually plays the audio and posts the information to the lock screen:


- (IBAction)playButtonPress:(id)sender {
    
    [audioPlayer play];
    
    Class playingInfoCenter = NSClassFromString(@"MPNowPlayingInfoCenter");
    
    if (playingInfoCenter) {

        
        NSMutableDictionary *songInfo = [[NSMutableDictionary alloc] init];
        
       
        MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage: [UIImage imagedNamed:@"AlbumArt"]];
        
        [songInfo setObject:@"Audio Title" forKey:MPMediaItemPropertyTitle];
        [songInfo setObject:@"Audio Author" forKey:MPMediaItemPropertyArtist];
        [songInfo setObject:@"Audio Album" forKey:MPMediaItemPropertyAlbumTitle];
        [songInfo setObject:albumArt forKey:MPMediaItemPropertyArtwork];
        [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songInfo];


    }
}

Let’s go through this line by line starting with line 5. Lines 5 & 7 of our code make sure the class MPNowPlayingInfoCenter exists since this functionality was just added in iOS 5. Next, we create an NSMutableDictionary called songInfo that will contain the information for the lock screen. Next we create an MPMediaItemArtwork item that will store the image. We set our information on lines 13-16. These are the properties that display on the lock screen. Something to keep in mind is there are several 3rd party peripherals that interact with the iPhone/iPod that play music that might pull this information. There are a few additional properties you can assign that may be accessed by other devices and you can read about those in the Apple docs. Last and certainly not least, the magic happens with line 17 as we add the information to the lock screen! Viola!

Path 2.0 style animated splash screen (default.png)

I don’t use splash screens often but when I do, I want them to open like a book.

In all truth, I’m not a big fan of splash screens and even Apple recommends using a default.png that shows the controls (with no text) of the application:

Display a launch image that closely resembles the first screen of the application. This practice decreases the perceived launch time of your application.

Avoid displaying an About window or a splash screen. In general, try to avoid providing any type of startup experience that prevents people from using your application immediately.

from HIG Guidelines

However, some people love them and one app in particular has a nice implementation splash screen — Path 2.0. When you open Path, you’re greeted with their logo on a red version of the Apple linen texture that animates open like a book (or journal as that’s what Path considers themselves to be).

You can get the source for this project here: https://github.com/jaysonlane/OpenBook

Before we begin, let me preface this with a disclaimer: I am very new to animations in Cocoa so bear with me. If you spot unnecessary or inefficient code, please leave a comment and I’ll tidy it up.

If you haven’t seen the animation, hop on the app store and pick up a copy to see what we’re trying to accomplish. I’ve created a default png that we can use cleverly titled Math (like a Math book that opens, right?) You can download that here (retina) and here.

To get started, let me explain “the trickery” behind what we’ll be doing: we’re going to use the normal default splash system in place to display our default.png. In the App Delegate, once the application has finished launching, we’re going to create a UIImageView on top of our view of that same default.png. We’ll then animate that UIImageView, to rotate open to reveal our view.

So let’s go:

Create a new project, I created one using the single view template but this will work with whatever. Go ahead and set your default.png and default@2x.png to the images supplied. You can do this by clicking the project in the navigation pane on the left, click the Target and scroll down to launch images:

Open your AppDelegate.m and add the following code to your application didFinishLaunching or application didFinishLaunchingWithOptions function:


    //1. add the image to the front of the view...
    UIImageView *splashImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    [splashImage setImage: [UIImage imageNamed:@"Default"]];
    [self.window addSubview:splashImage];
    [self.window bringSubviewToFront:splashImage];

    //2. set an anchor point on the image view so it opens from the left
    splashImage.layer.anchorPoint = CGPointMake(0, 0.5);

    //reset the image view frame
    splashImage.frame = CGRectMake(0, 0, 320, 480);

    //3. animate the open
    [UIView animateWithDuration:1.0
                          delay:0.6
                        options:(UIViewAnimationCurveEaseOut)
                     animations:^{

                         splashImage.layer.transform = CATransform3DRotate(CATransform3DIdentity, -M_PI_2, 0, 1, 0);
                     } completion:^(BOOL finished){

                         //remove that imageview from the view
                         [splashImage removeFromSuperview];
                     }];

Three things are happening here…

1) We create a new UIImageView and add it to the top of the view
2) We set an anchor point on the left side of the image to make it open from the left and then reset the frame to the full size of the view
3) We animate the UIImageView and remove it from the view on completion

That’s it, it’s that simple.

NSDateFormatter

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

[dateFormatter setDateFormat:@"YYYY-MM-dd"];

I’ve enjoyed PHP’s date() documentation but have yet to find comprehensive documentation for NSDateFormatter. I have not verified all of the following so if you find an error, leave a comment and I’ll try to get it fixed as quickly as possible. A ton of this information was gathered from Alex Curylo.

Character Description Example Returned Value
a Ante Meridiem and Post Meridiem AM/PM
A Millisecond of the Day 0..86399999
c/cc Numeric representation of day of the week 1..7
ccc Abbreviated day of the week Sun, Mon, Tue…
cccc Written day of the week Sunday, Monday, Tuesday…
d 0 padded Day of Month 1..31
D 0 padded Day of Year 01..366
e Day of Week with leading zero 01..07
E..EEE Sun, Mon, Tue…
EEEE Sunday, Monday, Tuesday…
F Week of Month, first day of week = Monday, with leading zero 1..5
g Julian Day Number (number of days since 4713 BC January 1)
G..GGG Era Designator Abbreviated BC, AD
GGGG Era Designator Before Christ, Anno Domini
h Hour (12 hr) with leading zero 1..12
H Hour (24 hr, starting at 0) with leading zero 0..23
k Hour (24 hr, starting at 1) with leading zero 1..24
K Hour (12 hr) with leading zero 0..11
m Minute with leading zero 0..59
s Second with leading zero 0..59
S Rounded sub-second
v..vvv General GMT Timezone Abbreviation GMT
vvvv General GMT Timezone Name Atlantic/Azores
z..zzz Specific GMT Timezone Abbreviation
zzzz Specific GMT Timezone Name
Z RFC 822 Timezone +0000
L..LL Month with leading 0 01..12
LLL Month abbreviation Jan, Feb, Mar…
LLLL Full Month January, February, March…
w Week of Year, 1st day of week is Sunday, 1st week of year starts from the last Sunday of last year, with leading zero 01..53
W Week of Month, 1st day of week = Sunday, with leading 0 01..05
M..MM Month of the year 1..12
MMM Month Abbreviated Jan, Feb, Mar…
MMMM Full Month January, February, March…
q..qq Quarter of the year 1..4
qqq Quarter abbreviated Q1, Q2, Q3, Q4
qqqq Quarter written out 1st quarter, 2nd quarter, 3rd quarter…
Q..QQ Quarter of the year 1..4
QQQ Quarter abbreviated Q1, Q2, Q3, Q4
QQQQ Quarter written out 1st quarter, 2nd quarter, 3rd quarter…
y/yyyy Full Year 2012, 2013, 2014…
yy..yyy 2 Digits Year 12, 13, 14…
Y/YYYY Full Year, starting from the Sunday of the 1st week of year 2012, 2013, 2014…
YY/YYY 2 Digits Year, starting from the Sunday of the 1st week of year
u Year