How to display image on iPhone using UIImageView and UIScrollView

Leave a comment

These are abbreviated notes from the Lecture 8 Imaginarium demo of Paul Hegarty’s excellent iPhone course. For the full walk through go there.

After you’ve created a blank single view project with an ImaginariumViewController….

Drag an Image View into the ViewController view area.

Drag an image into your project.

Add image to display.

Note – it will automatically scale the image to fit the view (will change the aspect ratio).

Change to only show top left

Now the image aspect ratio is respected, but the image is so big we only start showing the top left. So now we’ll add a scroll bar.

Select the image view (use doc view pop out on right of story board if you need to make sure you have the right view).

And click Editor -> Embed In -> Scroll View

Note how imageView is now embedded in scrollView.

Our scroll view struts and springs are now out of wack.

Fix them so they expand and use the entire area.

If we run this now we’ll see our image but no scrolling.

ScrollView has to have it’s content size set.

This scroll view currently doesn’t know how big an area to scroll over. So we need to set it (set the content area, and then set the frame of the image view so it’s in the right spot).

Going to talk to these guys from our ViewController. Therefore we need outlets.

Note you can drag the outlets from the docView we saw earlier.
Call them imageView and scrollView and stick them in the private interface of the ViewController.

Note when you do this it will auto create the synthesize and it will also add itself to the ViewDidUnload() the low memory thing.

Now use viewDidLoad to set your content size (the size of the image) and it’s frame to be the full size.

ImaginariumViewController.m

-(void)viewDidLoad
{
    [super viewDidLoad];
    self.scrollView.contentSize = self.imageView.image.size;
    self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
}

Now when we run should work.

Bonus points – zoom

So how to we get this thing to zoom?

Set the min and max zoom on the scrollView.

Set the delegate.

@interface ImaginariumViewController()  

Implement the zoom method.

-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    // return which subview we want to zoom
    return self.imageView;
}

Now set ourselves as the delegate.

-(void)viewDidLoad
{
    [super viewDidLoad];
    self.scrollView.delegate = self;

Note you can also set the delegate entirely within the story board using the doc view by dragging the scrollView to the controller.

Should now be able to zoom.

Code in it’s entirety.

ImaginariumViewController.m

#import "ImaginariumViewController.h"

@interface ImaginariumViewController()  <UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
@end

@implementation ImaginariumViewController
@synthesize imageView;
@synthesize scrollView;

-(void)viewDidLoad
{
    [super viewDidLoad];
    self.scrollView.delegate = self;
    self.scrollView.contentSize = self.imageView.image.size;
    self.imageView.frame = CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
}

-(UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView
{
    // return which subview we want to zoom
    return self.imageView;
}

- (void)viewDidUnload {
    [self setImageView:nil];
    [self setScrollView:nil];
    [super viewDidUnload];
}
@end

How to iPhone protocol and delegate

Leave a comment

This material is based on Paul Hegarty’s Lecture 5 and 6 iPhone course. For full explanation go there – these are abbreviated notes.

Say we have a View (FaceView) which knows how to draw a happy face but the level of it’s happiness (or smile) is currently hardwired to be 0 (not very happy).

And we’d like some externtal delegate to be able to set it for us.

Because Views can’t talk directly to controllers in iOS one way to do this is using protocols and delegates.

The view defines a protocol, which the controller implements thereby acting as the datasource for the view. Here’s how you hook it up.

1. Define the protocol and property.

FaceView.h

#import <UIKit/UIKit.h> 

@class FaceView;

@protocol FaceViewDataSource
- (float)smileForFaceView:(FaceView *)sender;
@end

@interface FaceView : UIView
@property (nonatomic, weak) IBOutlet id  dataSource;
@end

NB: Remember to synthesize the datasource in your .m file.

FaceView.m

@implementation FaceView
@synthesize dataSource = _dataSource;

What this basically says is create a protocol called smileForFaceView which returns a float (our smiliness) and takes as an input ourselves as the sender.

And then make that a publicly consumable property that others can register themselves for.

2. Use the delegate in your implementation.

For us our delegate is going to be used when we draw the smile in our drawRect function. So we replace the hard coded smile with:

FaceView.m

    //float smile = 100;
    float smile = [self.dataSource smileForFaceView:self];

3. Set controller as delegate.

So now FaceView is hooked up to use it’s delegate. Now we need to set our controller up to act as the delegate. This means having our controller say that they implement our FaceView protocol.

We could put in in our header file but because it’s private to our controller we stick it in our private interface.

HappinessViewController.m

@interface HappinessViewController() <FaceViewDataSource>

4. Do the implementation.

HappinessViewController.m

- (float)smileForFaceView:(FaceView *)sender {
    // set smile
}

5. Set delegate to be the controller.

Good time to do this is in the setter for our view in our controller.

HappinessViewController.m

-(void) setFaceView:(FaceView *)faceView
{
    _faceView = faceView;
    self.faceView.dataSource = self;
}

Voila! Now our controller is hooked up and ready to serve our view as it’s datasource.

Test

Add a button called refresh that when pressed sets the happiness.

- (IBAction)refresh:(id)sender {
    self.happiness = 100;
}

Should now see smile instead of frown (default of 0).

How segue in iOS and pass data from one ViewController to another

Leave a comment

Say we have a ViewController (Doctor), and we want to segue to another (Happiness) when the user clicks a Happy or Sad button.

How could we do it?

Add segues.

While holding down the ‘control’ key we can drag from the buttons on the left MVC to the MVC on the right and select the ‘push’ model.

Give segues identifier names.

Assign each segue a name so we can tell one from the other (i.e Happy, Sad).

Add Navigation Controller.

If you ran this now it wouldn’t work. Segues only work when they are within some kind of navigation controller.

Click on the MVC on the left (the one that is going to start the application and go)

Editor -> Embed in -> Navigation Controller

If you run now you should see transitions when you click on Happy/Sad buttons.

Prepare for segue

To pass data to our new MVC we need to set stuff up in our prepareForSeque method.

DoctorViewController.m


#import "DoctorViewController.h"
#import "HappinessViewController.h"

@implementation DoctorViewController

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    NSLog(@"prepareForSegue: %@", segue.identifier);

    if ([segue.identifier isEqualToString:@"Happy"]) {
        [segue.destinationViewController setHappiness:100];
    } else if ([segue.identifier isEqualToString:@"Sad"]) {
        [segue.destinationViewController setHappiness:0];
    }
}

@end

In here the segue.destinationViewController points to the ViewController we are going to navigate to and it is of type ‘id’ (a special type in iOS objective C which could be any object).

Because we know where we are navigating to HappinessViewController we can treat segue.destinationViewController as if it were our HappinessViewController and call methods on it like setHappiness.

That’s how we pass data from one MVC to another. Through the segue by calling set property methods directly on our new ViewController.

And we can test that this gets passed by placing a log call in our HappinessViewController.

HappinessViewController.m

-(void)setHappiness:(int)happiness
{
    _happiness = happiness;
    NSString* result = [NSString stringWithFormat:@"%d", happiness];
    NSLog(@"Got happy %@", result);
    self.display.text = result; 
}

Now there’s one bug I haven’t been able to figure out yet. Which is how to refresh the view once it gets set here.

The self.display label is nil but once I figure it out I will come back up here and update.

For a much better walk through of who segues work check out Paul Hegarty’s Lecture 6 as part of the Stanford iPhone class series.

How to add a model to a ViewController

Leave a comment

Add the property to the ViewController header.

CircleViewController.h

#import <UIKit/UIKit.h>

@interface CircleViewController : UIViewController
@property (nonatomic) int radius; // 1 small circle, 100 big
@end

And synthesize it in our code .m file.

CircleViewController.m

#import "CircleViewController.h"
@implementation CircleViewController
@synthesize radius = _radius;
@end

You can also optionally reset your view for display if you model changes like so:

-(void)setHappiness:(int)happiness
{
    NSLog(@"setHappiness: %@", @"1");
    _happiness = happiness;
    [self.faceView setNeedsDisplay];
}

How to create a new iPhone ViewController and View

Leave a comment

Here’s a cheat sheet I use to remind myself how to create a ViewController and View in iOS5.

1. Create the View Controller.

Drag View Controller control onto story board.

Create View Controller class.

Assign the class to the controller.

2. Create the View.

Drag generic view onto View Controller.

Create View class.

Assign view class to generic view.

3. Connect View Controller to View.

Do this via a private interface on the View Controller. Note this property has an IBOutlet marker to support XCode dragging of controller onto view.

PhotoViewController.m

#import "PhotoViewController.h"
#import "PhotoView.h"

@interface PhotoViewController()
@property (nonatomic, weak) IBOutlet PhotoView *photoView;
@end

@implementation PhotoViewController
@synthesize photoView = _photoView;
@end

Now go back to the story board and, holding down the ‘control’ key, drag the yellow circle with the white paper inside up into the view.

Optional: Move AppDelegate classes to Supporting Files.

You don’t really need these cluttering up your file structure so you can optionally move them into ‘Supporting Files’.

That’s it! You’ve now got a controller hooked up to it’s view.

How to create background color gradient using adobe illustrator

Leave a comment

To create a repeating background for your website using a gradient affect that looks something like this:

do the following.

Adobe illustrator CS5

Draw a square.

Open the gradient window (Window -> Gradient)

Click the gradient box (will apply black to white gradient).

Open the color pallette (Window -> Color) and get both the color and gradient window on screen at the same time (tricky because Adobe UI is terrible).

Once you’ve got them both up, click and drag the colors you want for your gradient from the color palette down to the ends of the gradient.

Transform and slim the gradient until your happy. Save this image somewhere you can access from your website. Remember to reduce the size of your canvas (Shift -O) to make sure your image is slim when you export it.

CSS

Now apply the following CSS to the body of your website:

body {
		background-image: url('../images/bg_body.png');
		background-repeat: repeat-x;
		background-color: #c9efed;
		height: 100%;
}

This takes the gradient we just created, and repeats it across the screen and applies a default color to anything below your gradient image where is runs out.

Voila! That’s it. You’ve now got a nice background to build off of.

WordPress 2011 in review report

Leave a comment

The WordPress.com stats helper monkeys prepared a 2011 annual report for this blog.

Here’s an excerpt:

The Louvre Museum has 8.5 million visitors per year. This blog was viewed about 77,000 times in 2011. If it were an exhibit at the Louvre Museum, it would take about 3 days for that many people to see it.

Click here to see the complete report.

How to break on any raised exception while debugging iPhone app

Leave a comment

In Paul Hegarty’s excellent CS 193 iPhone Application Development lectures, #40 has some great tips on debugging.

In it Paul shows a really cool way of configuring the XCode debugger so that any time an exception is raised, the debugger stops instantly and shows you the offending line of code.

Simply open up your XCode (4.2.1) breakpoint navigator:

Click the plus sign at the bottom and add an Exception Break Point:

And then just take the default All Exceptions, Break On Throw

Voila! Now whenever an exception is raised, your debugger will stop instantly and point out the offending line.

How do rails environments work?

Leave a comment

Rails environments are wonderful. But they can be a bit confusing do to some inconsistency in terms of which environments are affected when you run certain rake tasks.

After some digging I think I figured it out.

db:create – affects both development and test environments
db:drop – only affected development (though this has changed)
db:migration – runs against your current environment (usually development)

hence the need for
db:test:prepare (to apply migrations against your test environment)

So in summary, you always need to specify the environment your rake tasks run against

$ rake foo RAILS_ENV=test

With the exception of db:create and db:drop above.

Links that helped:

https://github.com/rails/rails/pull/2419
http://railsforum.com/viewtopic.php?id=6648
http://jasonseifer.com/2010/04/06/rake-tutorial

How to setup Rails3 postgres on mac

2 Comments

Wanting to align with Heroku I decided to setup a local instance of postgres.
It was more complicated than I would have liked, but here are some sketchy notes that might help if you need to go through the same thing.

Install postgres

$ brew install postgresql

After trying the EnterpriseDB one click deploy I found the homebrew install most stable.

Create Rails3 app with postgres as database

$ rails new pg -d postgres

Create new postgres database user

$ cd
$ sudo su postgres
Password:
$ createuser jr
$ Shall the new role be a superuser? (y/n) y
$ exit

if you get a getcwd: cannot access parent directories: Permission denied
just type ‘cd’ or ‘cd /’ and goto a directory where permissions aren’t an issue.

Create databases

$ sudo su postgres
Password:
$ psql template1
Password:

template1=# \l
template1=# CREATE DATABASE pg_development;
template1=# CREATE DATABASE pg_test;
template1=# \q

Login to terminal

$ psql -U postgres -d pg_development
Password:

config/database.yml

development:
adapter: postgresql
encoding: unicode
database: pg_development
pool: 5
username: postgres
password: root

test:
adapter: postgresql
encoding: unicode
database: pg_test
pool: 5
username: postgres
password: root

This was all setup and pre-populated. Only had to set username and password.

Test

$ rake db:create
$ rails generate scaffold Post name:string title:string content:text
$ rake db:migrate

Should be good to go. If you run into problems let me know and I will try to keep this up to do.

kill hanging postgres processes

Sometimes I have to manually kill postgres instances when I do a redeploy.
Pattern I follow is:
> db.sh (rebuild database)
> sudo kill -9
> manually restart server using pgadmin
> restart local rails server

– it’s a pain and I will update this when I find a better way

stackoverflow
postgres

Links that helped
http://www.funonrails.com/2011/03/getting-started-with-rails-3-postgres.html
http://www.mcbsys.com/techblog/2011/10/set-up-postgresql-for-rails-3-1/
http://devcenter.heroku.com/articles/local-postgresql#macintosh

Older Entries

Follow

Get every new post delivered to your Inbox.