Touches

By Marcos on July 26th, 2011
No

Touches are handled by three methods:

  • touchesBegan:
  • touchesMoved:
  • touchesEnded:

 

To have access to touches you need to code these 3 methods (or one/two of them).

The code is very simple:

1
</p><p>- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {</p><p>}</p><p>- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {</p><p>}</p><p>- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {</p><p>}</p><p>

touchesBegan: will be called whenever user touch the screen with one finger, and each time new touch is declared for example with the second finger, nose ear, battery, foot…

touchesEnded: will be called whenever any single touch is ended

touchesMoved: hmmm it’s not so clear as you might think. Yes, this method will be called if any finger moves while touching the screen, but on real device this method is called almost immidietely after touchesBegan. Why is that? On iPhone simulator mouse plays role of the finger, so you can press and release the mouse/touch-pad button and both touchesBegan and touchesEnded will be called, but not touchesMoved provided that you won’t move a pointer. If you touch an iPhone / iPod screen in 99% the coordinates of where the touch started and ended will be different, so meanwhile touchesMoved will be called.

You probably woud like to know what are the touch coordinates, it’s very easy to get them. Extend any of above three methods with this code:

1
</p><p>UITouch *touch = [touches anyObject];</p><p>CGPoint touchCoordinates = [touch locationInView:self.view];</p><p>

touchCoordinates.x and touchCoordinates.y give you information you need.

If you would like to have details of more than single touch (you can touch the screen with as many fingers you want), this might be helpful:

1
</p><p>NSSet *allTouches = [event allTouches];</p><p>UITouch *singleTouch;</p><p>for (int i = 0; i < [allTouches count]; i++) {</p><p>singleTouch = [[allTouches allObjects] objectAtIndex:i];</p><p>// whatever you need goes here</p><p>}</p><p>

If you would like to simply know how many fingers are touching the screen use [allTouches count]; with first line of above example.

If you want to do something when users double tap the screen for example try:

1
</p><p>if ([touch tapCount] == 2) {</p><p>// whatever you need goes here</p><p>}</p><p>

You can use only tapCount for the single touch. Taps aren’t counted for multiple touches.

 

Now something more interesting. How to check if user touched an object like image, label…? Before you enter any code in the attributes in Interface Builder of your item enable option: User Interaction Enabled and Multiple Touches if needed. views have User Iteraction enabled by default. You can also do it in XCode:

1
</p><p>myObject.userInteractionEnabled = YES;</p><p>myObject.multipleTouchEnabled = YES;</p><p>

Once User Interaction is enabled you can use if statement to perform any task:

1
</p><p>if ([touch view] == myObject) {</p><p>// whatever you need goes here</p><p>}</p><p>

touchessimulator 161x300 Touches

iOS Advanced Programming: Event Kit Framework

By Marcos on July 18th, 2011
No

In today’s tutorial we are going to cover the Event Kit Framework and how to add an event to the calendar.

The Event Kit Framework is the way Apple wants us to display or create a calendar entry. With this they are not trying to replace the calendar app, they are trying to give us a way to create an appointment from our app and add it to the calendar app.

To explain this I am going to create a calendar event programmatically. The only problem is that we are not going to be able to test it in the simulator because it doesn’t have a calendar app. To test it you will have to pay $99 to Apple.

Open up Xcode and create a View-Based Application for iPhone. I’m going to call mine “EventApp”.

Adding the framework

The Event framework is not added by default. You have to right click over the “Frameworks” folder in “Groups and Files” and select Add->Existing Frameworks then find EventKit.framework and click the “Add” button.

image 1 iOS Advanced Programming: Event Kit Framework

Writing the Code

Now in the EventAppViewController.m import EventKit.

1
</p><p>#import</p><p>

 

Now create a method that will be called when the user touches the “Create event” button that we are going to add later to our interface.

1
</p><p>-(IBAction) newEvent {</p><p> </p><p>}</p><p>

Remember that it must also be added to the .h file as well.

First add the object that is going to give us access to the events database, an EKEventStore.

1
</p><p>EKEventStore *eventDB = [[EKEventStore alloc] init];</p><p>

 

Then we create a new event object:

1
</p><p>EKEvent *myEvent  = [EKEvent eventWithEventStore:eventDB];</p><p>

 

Now we set some basic properties:

1
</p><p>myEvent.title     = @"New Event";</p><p>myEvent.startDate = [[NSDate alloc] init];</p><p>myEvent.endDate   = [[NSDate alloc] init];</p><p>myEvent.allDay = YES;</p><p>

 

I’m setting the start date and end date the same because it is not going to last more than one day and later I it will be an all-day event.

Next we must specify a calendar for that event. I am going to set it to the default calendar.

1
</p><p>[myEvent setCalendar:[eventDB defaultCalendarForNewEvents]];</p><p>

 

Before we save the event we need to check for errors:

1
</p><p>NSError *err;</p><p>[eventDB saveEvent:myEvent span:EKSpanThisEvent error:&err];</p><p>

 

Now we test to see if there are any errors. If there are no errors we tell the user that the event was successfully created.

1
</p><p>if (err == noErr) {</p><p>UIAlertView *alert = [[UIAlertView alloc]</p><p>initWithTitle:@"Event Created"</p><p>message:@"Yay!"</p><p>delegate:nil</p><p>cancelButtonTitle:@"Okay"</p><p>otherButtonTitles:nil];</p><p>[alert show];</p><p>[alert release];</p><p>}</p><p>

 

Apple strongly recommends that you notify the user that the event was created. If you create events in the background and you don’t tell the user, Apple will probably reject your app from the App Store, so it is always a good idea to do this.

And last we release the objects:

1
</p><p>[startDate release];</p><p>[endDate release];</p><p>[eventStore release];</p><p>

 

The final look of the method should be this:

1
</p><p>-(IBAction) newEvent {</p><p> </p><p>EKEventStore *eventDB = [[EKEventStore alloc] init];</p><p> </p><p>EKEvent *myEvent  = [EKEvent eventWithEventStore:eventDB];</p><p> </p><p>myEvent.title     = @"New Event";</p><p>myEvent.startDate = [[NSDate alloc] init];</p><p>myEvent.endDate   = [[NSDate alloc] init];</p><p>myEvent.allDay = YES;</p><p> </p><p>[myEvent setCalendar:[eventDB defaultCalendarForNewEvents]];</p><p> </p><p>NSError *err;</p><p> </p><p>[eventDB saveEvent:myEvent span:EKSpanThisEvent error:&err];</p><p> </p><p>if (err == noErr) {</p><p>UIAlertView *alert = [[UIAlertView alloc]</p><p>initWithTitle:@"Event Created"</p><p>message:@"Yay!?"</p><p>delegate:nil</p><p>cancelButtonTitle:@"Okay"</p><p>otherButtonTitles:nil];</p><p>[alert show];</p><p>[alert release];</p><p>}</p><p>}</p><p>

 

Now let’s go to interface builder to create the GUI for our App.

Building the Interface

Open EventAppViewController.xib in the Resources folder.

Add a Round Rect Button and put some text in it.

image 2 iOS Advanced Programming: Event Kit Framework

Then connect it to the newEvent method.

Save and quit Interface Builder and we are done.

Conclusion

That was easy, wasn’t it?

Apple also included a UI kit for creating events that looks exactly like the calendar app, but it is so easy that i don’t need to explain it, i’m going to leave it to you as homework.

Image Processing Tricks

By Marcos on June 24th, 2011
No

Recently there have been some interesting developer news related to working with images on the iPhone.

  • First there is Chris Greening’s open source project simple-iphone-image-processing, that provides a set of common image processing tasks .
  • Today I listened to the Mobile Orchard’s podcast Interview with Paul Cantrell, and the discussion was about UIKit, views, layers, etc. This was the most enlightening information I’ve come across on this topic ever. Highly recommended.

So, I thought I’d contribute a few UIImage routines that I’ve found useful.

Combine two UIImages

To add two UIImages together you need to make use of Graphics Context.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (UIImage *)addImage:(UIImage *)image1 toImage:(UIImage *)image2 {

UIGraphicsBeginImageContext(image1.size);
// Draw image1	[image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];
// Draw image2	[image2 drawInRect:CGRectMake(0, 0, image2.size.width, image2.size.height)];
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultingImage;}

Create a UIImage from a part of another UIImage

This requires a round-trip to Core Graphics land:

1
2
3
4
5
6
7
8
9
10
11
12
13
- (UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect {

CGImageRef sourceImageRef = [image CGImage];

CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);

UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

CGImageRelease(newImageRef);	return newImage;}

Save UIImage to Photo Album

This is just a one-liner:

1
UIImageWriteToSavedPhotosAlbum(image, self, @selector(imageSavedToPhotosAlbum: didFinishSavingWithError: contextInfo:), context);

And to know if the save was successful:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- (void)imageSavedToPhotosAlbum:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {

NSString *message;	NSString *title;

if (!error) {

title = NSLocalizedString(@"SaveSuccessTitle", @"");

message = NSLocalizedString(@"SaveSuccessMessage", @"");

} else {

title = NSLocalizedString(@"SaveFailedTitle", @"");

message = [error description];

}

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title													message:message												   delegate:nil										  cancelButtonTitle:NSLocalizedString(@"ButtonOK", @"")										  otherButtonTitles:nil];

[alert show];

[alert release];}

 

No

Question: As a graphic designer I often have to design icons, logos, launch and background images for iPhone applications. Latest apps run on iPhone 3G, iPhone 3GS, iPod Touch 3, iPhone 4GS and iPad and there is a big boom and confusion in this area. I use Adobe Photoshop CS4. What size and type of images do I have to create for such a project?

 

Answer: We use the following table for our iPhone/iPad projects when the OS target is 3.2 or above. The table is updated for iOS 4.3 and Xcode 4:

Name Size (pixels) Platform
Icon.png 57 x 57 Universial application icon
Icon-settings.png 29 x 29 Universial application icon for settings area. Alternative name: Icon-Small.png
Icon~ipad.png 72 x 72 iPad application icon. Alternative name: Icon-72.png Add some smaller (iPad doc: 64×64, other optional 32×32, 24×24, 16×16) custom icons to your project. See comments.
Icon-spot~ipad.png 50 x 50 iPad icon for spotlight search. Alternative name: Icon-Small-50.png iPhone OS trims 1 pixel from each side and adds a drop shadow. The actual size is 48×48 pixels.
iTunesArtwork.png 512 x 512 Universial application icon for iTunes App Store. Uploaded separately to iTunes. It’s included in the app bundle too, file name: iTunesArtwork. In an iPad application iPhone OS uses this image to generate the large (320×320) document icon if it is not supplied otherwise.
Default.png 320 (w) x 480 (h) iPhone/iPod 2, 3 portrait launch image
Default@2x.png 640 (w) x 960 (h) iPhone 4 hi-res portrait launch image
Default~ipad.png 768 (w) x 1004 (h) iPad. Specifies the default portrait launch image. This image is used if a more specific image is not available. Use full size template (768×1024) to design this launch image. The 20 pixels height statusbar is on by default and occupies the top of the screen, aka the 1004 rows vs. 1024.
Optional icons and images:
Icon@2x.png 114 x 114 iPhone 4 hi-res application icon
Icon-settings@2x.png 58 x 58 iPhone 4 hi-res application icon for settings/search area
Icon-doc.png 22 (w) x 29 (h) Universial document icon
Icon-doc@2x.png 44 (w) x 58 (h) iPhone 4 hi-res document icon
Icon-doc~ipad.png 64 x 64 iPad document icon (small)
Icon-doc320~ipad.png 320 x 320 iPad document icon (large)
Background-xxx.png 320 (w) x 480 (h)
640 (w) x 960 (h)
768 (w) x 1024 (h)
iPhone/iPod Touch 2, 3 background image,
iPhone 4 background image, full size
iPad background image, full size. For most projects the status bar is hidden, so use full screen size by default.
Default-PortraitUpsideDown~ipad.png 768 (w) x 1004 (h) iPad. Specifies an upside-down portrait version of the launch image. The height of this image should be 1004 pixels and the width should be 768. This file takes precedence over the Default-Portrait.png image file for this specific orientation.
Default-LandscapeLeft~ipad.png 1024 (w) x 748 (h) iPad. Specifies a left-oriented landscape version of the launch image. The height of this image should be 748 pixels and the width should be 1024. This file takes precedence over the Default-Landscape.png image file for this specific orientation.
Default-LandscapeRight~ipad.png 1024 (w) x 748 (h) iPad. Specifies a right-oriented landscape version of the launch image. The height of this image should be 748 pixels and the width should be 1024. This file takes precedence over the Default-Landscape.png image file for this specific orientation.
Default-Portrait~ipad.png 768 (w) x 1004 (h) iPad. Specifies the generic portrait version of the launch image. The height of this image should be 1004 pixels and the width should be 768. This image is used for right side-up portrait orientations and takes precedence over the Default~ipad.png image file. If a Default-PortraitUpsideDown.png image file is not specified, this file is also used for upside-down portrait orientations as well.
Default-Landscape~ipad.png 1024 (w) x 748 (h) iPad. Specifies the generic landscape version of the launch image. The height of this image should be 748 pixels and the width should be 1024. If a Default-LandscapeLet.png or Default-LandscapeRight.png image file is not specified, this image is used instead. This image takes precedence over the Default.png image file.

Typical icons are PNG files with 90 degree corners, but no transparency, no layers, and set to 72 PPI.  iPhone OS applies rounded corners, optionally shine, and other effects. If you have added these effects let your programmers know it. When you do not let the iPhone/iPad OS to apply the gloss to your icons, developers must add a key to info.plist calledUIPrerenderedIcon and make it checked. The standard bit depth is 24 bits + 8-bit alpha channel.

Designers and programmers alike understand now that the sizes of items on iPhone/iPad screens are not constants. Differences in screen size and zoom functionality are common place, but PNG format and 72 PPI is still the default. (PNG discards pixel density. Most image editors, including Adobe Photoshop, assume that an image’s pixel density is 72 if the information is not stored.)

iPad icons can be tricky. Some designers release the standard iPad icons only but fail to include some crisp small size icons as options for OS. Add some tiny iPad icons to your project in the sizes of 64×64, 32x32px, 24x24px and 16x16px. Programmers know how to include these files (see Info.plist).

You should know that when the user taps on the main application icon the app immediately starts to load. It’s important to make the launch time as short as possible. Every iPhone/iPad app should ship with a launch image which mimicks the interface by using a static image. The launch image should be as small a file as possible to ensure quick loading. Do not create image files in the megabyte territory.

 

Notes for developers:

In the Info.plist file developers specify the orientations the application supports along with the related launch images. If missing, they must add these lines:

1
2
3
4
5
6
7
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>

 

iOS documentation: “The image files used to represent icons and launch images must all reside in the root level of your bundle. How you identify these images to the system can vary, but the recommended way to specify your application icons is to use the CFBundleIconFiles key… In addition to the icons and launch image at the top level of your bundle, you can also include localized versions of those images in your application’s language-specific project subdirectories”. The filenames can be anything you want, but all image files must be in the PNG format.

1. If your iPhone application supports running in iOS 3.1.x or earlier, you cannot use the CFBundleIconFiles key to specify your icon files. You must create icons of the same size as listed in our table, but each image must be named as follows:

Icon.png – Application icon on iPhone or iPod touch
Icon-72.png – iPad application icon in a Universal application
Icon-Small.png - Search results and Settings icon on iPhone and iPod touch
Icon-Small-50.png – Search results in iPad applications

Since version 3.2 if you specify an Icon-Small.png or Icon-Small-50.png file in your bundle, the system prefers those icon files over the ones in the CFBundleIconFiles key and the iOS prefers the application icon defination in the CFBundleIconFiles key over any other one.

2. The iOS is finally making the move into resolution independence and your image objectsaren’t measured in pixels, but in points. Points don’t always correspond to pixels. The screen size of the iPhone 3 is 480×320, in both points an pixels. The iPhone 4′s screen size is 960×640 in pixels, but its logical screensize still remains at 480×320 in points. Keep your frame, point and size values in their original values and still support larger resolution devices. On iPhone 4 you may insert “@2x” in the name of the image file and it will be used automatically on the higher resolution devices. Use like “button1back@2x.png”. The simulator of XCode 3.2.6 still reports screen size of 320×480, but see what you have done… on a hires device.

Check out UIScreen class reference for properties of bounds and currentMode. The bounds property gives us the rectangle of the screen in points.The currentMode.size property represents the screen size in pixels. For example, since iOS 4, [UIImage imageWithContentsOfFile: ] recognises when an image has the ’2x’ version and displays it correctly.

3. In the Info.plist, at the CFBundleIconFiles key, if you do not specify the filename extensions for launch and icon images, you can avoid listing all of the 2x variations, and the Info.plist would look like this:

 

Displaying and Searching PDF Content on iPhone

By Marcos on June 24th, 2011
No

PDF parsing is a black art that most programmers avoid. “Madness lurks here.” They mumble to themselves quietly. Choosing instead to push their PDFs through UIWebViews and commit other crimes against humanity.

It doesn’t have to be this way, however. Parsing, displaying, and searching PDFs natively and at a low level is actually surprisingly easy if you’re not afraid to get your hands a little dirty with the Core Graphics PDF functions. I’m going to show you how.

Where’s it hiding?

The first thing to know is that in order to do this, you need to use Core Graphics calls. So you need to include the Core Graphics framework in your project, and in any files you want to use the calls, you have to include the CoreGraphics.h header. It’s probably also worthwhile to review the Core Foundation memory management rules.

Once you’ve done this, it’s very straight forward to read your PDF files and display them in a custom view. Let’s take a look at how we do that.

Initializing a PDF Document

To initialize a PDF document, you first have to use the call CGPDFDocumentCreate, passing in the URL to the document you want to open. Since NSURL is toll free bridged toCFURLRef, you can create a CFURLRef just using plain old NSURL like so:

NSString *pathToPdfDoc = [[NSBundle mainBundle]
                                        pathForResource:@"mypdf" ofType:@"pdf"];
NSURL *pdfUrl = [NSURL fileURLWithPath:pathToPdfDoc];

Then, to create the CGPDFDocumentRef, call CGPDFDocumentCreateWithURL:

CGPDFDocumentRef document = CGPDFDocumentCreateWithURL((CFURLRef)pdfUrl);

Displaying Pages

So now you have a document. To display the content of the document, you have to get the content in the form of pages. PDFs are already formatted by pages, so all you need to do is get at that data. Fortunately Core Graphics has functions for that too.

To get the total count of the pages in the document, you use the callCGPDFDocumentGetNumberOfPages, which takes as a parameter, the document you created above. So, for example:

size_t pageCount = CGPDFDocumentGetNumberOfPages(document);

Then, to get an individual page to display in your view, you use the functionCGPDFDocumentGetPage, passing the document and the page number you want. Like so:

CGPDFPageRef page = CGPDFDocumentGetPage(document, currentPage);

Note that the currentPage parameter here is 1 based, not 0 based as is the usual case in programming. This means that the first page of the PDF document is in fact, page 1, and not page 0.

Once you have the page, you can display it in your custom view. The only complicated part here is that on iPhone, the coordinate system is flipped compared to the Mac. This causes a problem because the Core Graphics PDF system uses the desktop coordinate system even on iPhone. (It’s yucky, I know.) The solution to this is to flip the page (this can be done in your drawRect method when you go to draw the content):

CGPDFPageRef page = CGPDFDocumentGetPage(document, currentPage);

CGContextRef ctx = UIGraphicsGetCurrentContext();

CGContextSaveGState(ctx);

CGContextTranslateCTM(ctx, 0.0, [self bounds].size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextConcatCTM(ctx,
           CGPDFPageGetDrawingTransform(page, kCGPDFCropBox, [self bounds], 0, true));

 

 

The key here is the call to CGContextScaleCTM. What we do, is we get the current drawing context, and then we scale it’s coordinate system on it’s y axis by -1.0. This, effectively, flips it upside down along it’s horizontal (x) axis.

Finally, we draw the page into the context using the CGContextDrawPDFPage function:

CGContextDrawPDFPage(ctx, page);
CGContextRestoreGState(ctx);


p. </div>

So basically, a full on @drawRect@ method for a custom view that draws content from a PDF page, looks something like this:

<div>
bc.. -(void)drawRect:(CGRect)inRect;
{
    if(document)
    {
        CGPDFPageRef page = CGPDFDocumentGetPage(document, currentPage);

        CGContextRef ctx = UIGraphicsGetCurrentContext();

        CGContextSaveGState(ctx);

        CGContextTranslateCTM(ctx, 0.0, [self bounds].size.height);
        CGContextScaleCTM(ctx, 1.0, -1.0);
        CGContextConcatCTM(ctx,
                         CGPDFPageGetDrawingTransform(page, kCGPDFCropBox,
                          [self bounds], 0, true));

        CGContextDrawPDFPage(ctx, page);
        CGContextRestoreGState(ctx);
    }
}


p. </div>

That's all there is to it!

Searching PDFs

One of the things that seems to be particularly scary to programmers is searching PDFs. I agree that it’s certainly not pleasant stuff to code, but it’s not hard either.

Now, I want to preface this by saying that I feel this code is a bit of a hack, but it definitely works, and seems to work quite well. Perhaps there’s a better way to do this, and if you know of one, please let me know. That said, however, here’s how I’ve done it.

The first thing to know is that PDF files are made up of operators which delineate the data within them. So, for example, all text in a PDF document is stored as glyphs and prefixed by operators of type either “Tj”, in the case of a string, or “TJ” in the case of an array of strings. Knowing this, you can access the PDF data as a stream and create a scanner which will call callback methods you specify when these operators are encountered. You can then retrieve the data after the operator and use it to build your search corpus.

That probably sounds intimidating, but it’t not. You start out by creating a class that will be your “page searcher.” This will hold the state for your search engine. Here’s the listing for the interface for this class:

#import <Foundation/Foundation.h>

@interface PDFSearcher : NSObject
{
    CGPDFOperatorTableRef table;
    NSMutableString *currentData;
}
@property (nonatomic, retain) NSMutableString * currentData;
-(id)init;
-(BOOL)page:(CGPDFPageRef)inPage containsString:(NSString *)inSearchString;
@end


p. </div>

Pretty straight forward stuff.  We use the currentData member to store the text of the page being scanned.  This is a member variable rather than a local variable because we're going to be using C functions to fill it in.  Don't worry, that'll make sense in a moment.

The @init@ method for the class actually creates the callback table:

<div>
bc.. -(id)init
{
    if(self = [super init])
    {
        table = CGPDFOperatorTableCreate();
        CGPDFOperatorTableSetCallback(table, "TJ", arrayCallback);
        CGPDFOperatorTableSetCallback(table, "Tj", stringCallback);
    }
    return self;
}

 

 

The arrayCallback and the stringCallback functions are C functions that will be called by the scanner. They’re shown here:

void arrayCallback(CGPDFScannerRef inScanner, void *userInfo)
{
    PDFSearcher * searcher = (PDFSearcher *)userInfo;

    CGPDFArrayRef array;

    bool success = CGPDFScannerPopArray(inScanner, &array);

    for(size_t n = 0; n < CGPDFArrayGetCount(array); n += 2)
    {
        if(n >= CGPDFArrayGetCount(array))
            continue;

        CGPDFStringRef string;
        success = CGPDFArrayGetString(array, n, &string);
        if(success)
        {
            NSString *data = (NSString *)CGPDFStringCopyTextString(string);
            [searcher.currentData appendFormat:@"%@", data];
            [data release];
        }
    }
}

void stringCallback(CGPDFScannerRef inScanner, void *userInfo)
{
    PDFSearcher *searcher = (PDFSearcher *)userInfo;

    CGPDFStringRef string;

    bool success = CGPDFScannerPopString(inScanner, &string);

    if(success)
    {
        NSString *data = (NSString *)CGPDFStringCopyTextString(string);
        [searcher.currentData appendFormat:@" %@", data];
        [data release];
    }
}


p. </div>

As you can see, these will be called when the operators fire.  When they do, we pop the data off the scanner, and add it to the searcher's corpus.  The userinfo pointer is actually pointing to our searcher object (based on the fact that we will pass it as the second parameter to @CGPDFScannerCreate@ in the next code).  So we can typecast it to a PDFSearcher and then access that currentData member (remember I said it would make sense later?).  

The actual search method looks like this:

<div>
bc.. -(BOOL)page:(CGPDFPageRef)inPage containsString:(NSString *)inSearchString;

{
    [self setCurrentData:[NSMutableString string]];
    CGPDFContentStreamRef contentStream = CGPDFContentStreamCreateWithPage(inPage);
    CGPDFScannerRef scanner = CGPDFScannerCreate(contentStream, table, self);
    bool ret = CGPDFScannerScan(scanner);
    CGPDFScannerRelease(scanner);
    CGPDFContentStreamRelease(contentStream);
    return ([[currentData uppercaseString]
          rangeOfString:[inSearchString uppercaseString]].location != NSNotFound);
}


p. </div>

Basically, we create a stream from the page data, then use that and our callback table to create a scanner.  We then scan the data.  It's at this point our currentData member is being filled with the data from the PDF as strings.  Finally, we just search that string for our search string.

Easy peezy.

Note: much of this code is only sight compiled.  I pulled it from some code I had, but it wasn't a straight across copy, so if you find an error, please let me know.

 

Getting the current date for iOS applications

By Marcos on May 28th, 2011
No

Last post we talked about the date related classes and how to create a date. Now, let’s find out how get the current date.

To get the current date we just sent the date message to the NSDate class:

1
NSDate *date = [NSDate date];

This will return an instance of the date object of the current date.

It’s a class method of NSDate. We still need to format it and convert it to a string.

1
2
3
4
5
6
7
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];

[dateFormat setDateFormat:@"HH:mm:ss zzz"];

NSString *dateString = [dateFormat stringFromDate:date];

Finally, we could use the string to update some label’s text.

1
labelTimeLeft.text = dateString;

That’s it.

 

Here’s all the code at once:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// get the current date

NSDate *date = [NSDate date];

 

// format it

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

[dateFormat setDateFormat:@"HH:mm:ss zzz"];

 

// convert it to a string

NSString *dateString = [dateFormat stringFromDate:date];

 

// free up memory

[dateFormat release];

 

// update a label’s text

labelTimeLeft.text = dateString;
Posted in

So this is a pain in the A** error that took me a while to figure out.

I had a UITabBarController with one of the tabs set to be a UIWebView and every time I would click on the UIWebView Tab, the application would crash with a lovely “Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[<UIViewController 0x4b37160> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key webView.” error.

I then went to the MainWindow.xib and clicked on the tab that had the UIWebView on it and behold, the parent class was set to the wrong View Controller class.  I changed the class and everything became kosher.

Just a pointer to anytime you get this type of error and you are using a UITabBarController, to go to the xib that has that UITabBarController and double check all the parent references for each of the tabs.

What follows is a trick to refactor a local variable, best used if the variable occurs many times within a local scope.

In the screenshot below, I highlighted the local variable dict and then entered Control-Command-T. Notice that each reference to this variable is now highlighted. An important note, you don’t need to necessarily highlight the first instance of the variable for this to work.

refactor1 How to change a variable name in iOS the right way

Once all the variables are highlighted, make the change to the new name and you’ll see all references updated in unison, see the figure below:

refactor2 How to change a variable name in iOS the right way

 

 How to change a variable name in iOS the right way

Tap your mouse anywhere outside the variable to complete the change.

 

Article Source: http://iphonedevelopertips.com/xcode/refactoring-to-change-a-local-variable-name.html

Applications created using the BlackBerry® WebWorks™ application platform have the ability to integrate with the data, features and capabilities from the underlying Java® development environment as well as the native BlackBerry® Smartphone through the use of special JavaScript® objects. These objects are called JavaScript extensions.

Existing examples of JavaScript extensions that are available for developers to use today include: audio, phone and SMS. More information about these extensions, which are part of the BlackBerry Open Source Project, can be found in the BlackBerry WebWorks API Reference guide.

This lab will demonstrate how developers can create their own JavaScript extensions to be used in their BlackBerry WebWorks applications. The complete source code for the JavaScript extension that will be created as part of this lab is attached at the end of this article.

The steps involved in completing this lab are:

1. Start a new BlackBerry Project

2. Add a package to the src folder

3. Create a ScriptableFunction Class

4. Create a Scriptable Class

5. Create a Widget Extension Class

6. Create a library.xml file

7. Export all source and resource files to a JAR

Start a new BlackBerry Project

You will use the BlackBerry® Java Plug-in for Eclipse® (with component pack 5.0) to create and package the source code of your JavaScript extension. This is a separate development tool from the BlackBerry WebWorks SDK, and is typically used by Java developers to write BlackBerry applications.

1. Open the BlackBerry Java Plug-in for Eclipse.

2. To keep your development environment organized, it is helpful to use a unique workspace for JavaScript extensions:

pic1 How to Build a BlackBerry WebWorks JavaScript Extension

3. Create a new Blackberry Project by selecting the “New” and “Project …” items from the File Menu.

pic2 How to Build a BlackBerry WebWorks JavaScript Extension

 

4. Name your project AlertExtension. Ensure that the BlackBerry JRE 5.0.0 is selected as the project specific JRE and click on the Finish button. If there is no option available for the 5.0 BlackBerry JRE, it means the 5.0 component pack is not installed in Eclipse. This component pack is required for building custom JavaScript extensions for BlackBerry WebWorks Applications, as they make use of new APIs introduced in 5.0.

pic3 How to Build a BlackBerry WebWorks JavaScript Extension

Add a package to the src folder

1. Expand the AlertExtension twistie within the Package Explorer window

2. Create a new package by right clicking on the src folder and selecting the “New” and “Package” menu items:

pic4 How to Build a BlackBerry WebWorks JavaScript Extension

 

3. Name the package samplecode and click on the Finish button:

pic5 How to Build a BlackBerry WebWorks JavaScript Extension

Create a ScriptableFunction Class

The ScriptableFunction class contains the actual implementation of the given feature’s functionality that you wish to include in this JavaScript Extension.

1. Create a new Java class by right clicking on the samplecode package name and selecting the “New” and “Class” menu items:

pic6 How to Build a BlackBerry WebWorks JavaScript Extension

 

2. Name your class AlertFunction and enable the public and final modifiers. Specify a superclass of net.rim.device.api.script.ScriptableFunction:

pic7 How to Build a BlackBerry WebWorks JavaScript Extension

3. Add the following code to the AlertFunction class. This logic will cause the BlackBerry smartphone to vibrate for a specified duration of time, provided as a command line argument:

1
</p><p>package samplecode;</p><p>import net.rim.device.api.script.ScriptableFunction;</p><p>import net.rim.device.api.system.Alert;</p><p>public final class AlertFunction extends ScriptableFunction {</p><p>public Object invoke(Object obj, Object[] args) throws Exception</p><p>{</p><p>if (!Alert.isVibrateSupported()) {</p><p>return UNDEFINED;</p><p>}</p><p>if (args.length == 1) {</p><p>int duration = ((Integer)args[0]).intValue();</p><p>Alert.startVibrate(duration);</p><p>}</p><p>return UNDEFINED;</p><p>}</p><p>}</p><p>

Create a Scriptable Class

Scriptable classes are registered with the JavaScript Engine that is used by the active BrowserField of a BlackBerry WebWorks application. The JavaScript extension enables a BlackBerry WebWorks application to communicate with underylying Java code. Calls to JavaScript methods are handled by the ScriptableFunction class, while calls for property or constant values can be returned as standard Objects (e.g. String or Integer).

1. Create a new Java class by right clicking on the samplecode package name and selecting the “New” and “Class” menu items.

2. Name the class AlertNamespace and enable the public and final modifiers. Specify a superclass of net.rim.device.api.script.Scriptable:

pic8 How to Build a BlackBerry WebWorks JavaScript Extension

3. This class will be used to associate JavaScript method or property keywords provided by a BlackBerry WebWorks application to Java-defined BlackBerry functionality. Add the following code to the AlertNamespace class. This sample demonstrates how to extend two methods named “isVibrateSupported” and “vibrate”:

1
</p><p>package samplecode;</p><p>import net.rim.device.api.script.Scriptable;</p><p>import net.rim.device.api.system.Alert;</p><p>public final class AlertNamespace extends Scriptable {</p><p>public static final String FIELD_VIBRATE_SUPPORTED = "isVibrateSupported";</p><p>public static final String FIELD_VIBRATE = "vibrate";</p><p>private AlertFunction callVibrate;</p><p> </p><p>public AlertNamespace() {</p><p>this.callVibrate = new AlertFunction();</p><p>}</p><p> </p><p>// The getField() function is called when the</p><p>//  dot '.' extender is used on your JavaScript object.</p><p>public Object getField(String name) throws Exception {</p><p>if (name.equals(FIELD_VIBRATE_SUPPORTED)) {</p><p>return new Boolean(Alert.isVibrateSupported());</p><p>} else if (name.equals(FIELD_VIBRATE)) {</p><p>return this.callVibrate;</p><p>}</p><p>return super.getField(name);</p><p>}</p><p>}</p><p>

Since a WebWorks application may run on BlackBerry smartphone models with different hardware configurations, it is considered good practice to always check whether a hardware feature is supported before it is used.

Create a WidgetExtension Class

The WidgetExtension class ties everything together and acts as the interface between the JavaScript engine of a BlackBerry WebWorks application and the custom logic you have defined in your AlertNamespace class.

1. Create a new Java class by right clicking on the samplecode package name and selecting the “New” and “Class” menu items.

2. Name your class AlertExtension and enable the public and final modifiers. Ensure that the AlertExtension class will be defined with an interface of net.rim.device.api.web.WidgetExtension. To add an interface, click on the add button next to the Interfaces field and then type in the full name of the interface:

pic9 How to Build a BlackBerry WebWorks JavaScript Extension

3. The AlertExtension class should contain the following method stubs:

* getFeatureList() – this method is called when the JavaScript extension is created. It will return an array containing the names of the available features that it provides.

* loadFeature() – this method is called when an application loads a resource that requires a <feature> id that you supplied in getFeatureList()

* register() – this method is called so that your extension can get a handle to the configuration document or BrowserField object if it needs it.

* unloadFeatures() – this method is available if you need to do any clean-up when your extension is unloaded.

4. Add the following code to the AlertExtension class:

1
</p><p>package widgetpackage;</p><p>import org.w3c.dom.Document;</p><p>import net.rim.device.api.browser.field2.BrowserField;</p><p>import net.rim.device.api.script.ScriptEngine;</p><p>import net.rim.device.api.web.WidgetConfig;</p><p>import net.rim.device.api.web.WidgetExtension;</p><p> </p><p>public final class AlertExtension implements WidgetExtension {</p><p>public String[] getFeatureList() {</p><p>String[] result = new String[1];</p><p>result[0] = "sample.alert";</p><p>return result;</p><p>}</p><p> </p><p>public void loadFeature(String feature, String version,</p><p>Document doc, ScriptEngine scriptEngine) throws Exception {</p><p>if (feature == "sample.alert") {</p><p>scriptEngine.addExtension("sample.alert", new AlertNamespace());</p><p>}</p><p>}</p><p> </p><p>public void register(WidgetConfig arg0, BrowserField arg1) {</p><p>// TODO Auto-generated method stub</p><p>}</p><p> </p><p>public void unloadFeatures(Document arg0) {</p><p>// TODO Auto-generated method stub</p><p>}</p><p>}</p><p>

Create a library.xml file

The purpose of the libary.xml file is to provide a public definition of feature names available within the given JavaScript extension, and an association to internal Java Class names. The latter is used by the BlackBerry WebWorks SDK when applications are packaged.

1. Create a new file by right clicking on the src folder within the AlertExtension project and selecting the “New” and “Other …” menu items.

2. Select XML from the New popup window and click on the Next button:

pic10 How to Build a BlackBerry WebWorks JavaScript Extension

 

3. Name your file library.xml:

pic11 How to Build a BlackBerry WebWorks JavaScript Extension

4. Add the following XML to the library.xml:

1
</p><p><?xml version="1.0" encoding="UTF-8"?></p><p><library></p><p><extension></p><p><entryClass>samplecode.AlertExtension</entryClass></p><p></extension></p><p><features></p><p><feature id="sample.alert" version="1.0.0" ></feature></p><p></features></p><p></library></p><p>

When a developer uses this JavaSCript extension in their WebWorks application, they will add the feature “sample.alert” to their configuration document (config.xml). The BlackBerry WebWorks SDK is then able to determine which internal class name is to be packaged into the compiled application (in this case “samplecode.AlertExtension”).

Export all source and resource files to a JAR

The final step is packaging any source and resource files that make up a JavaScript extension into a JAR file.

1. Export the relevant contents of AlertExtension project by right clicking on the src folder and selecting the “Export …” menu item:

pic12 How to Build a BlackBerry WebWorks JavaScript Extension

 

2. Choose to export resources to a JAR file on the local file system

pic13 How to Build a BlackBerry WebWorks JavaScript Extension

 

3. From the JAR File Specification popup window, only export the Java source files and resources found within the src/samplecode folder. Specify a descriptive name for the destination JAR file and click Finish.

pic14 How to Build a BlackBerry WebWorks JavaScript Extension

The JavaScript Extension is now complete, and ready to be used in a BlackBerry WebWorks Application. For more information on this topic, see the following article: Using JavaScript Extensions in your BlackBerry WebWorks Application development.

Blackberry Webworks vs Java SDK

By Marcos on April 29th, 2011
No

Webworks SDK pros: Reasonably easy to create compelling UIs and user experiences. The Javascript support is pretty reasonable as is CSS and HTML. It will be very familiar.

Java SDK pros: No much, its pretty barebones from a UI perspective. It is best if you are doing data or network intensive tasks. That said, using Javascript extensions in the Webworks SDK you can easily access custom Java routines from within Javascript so you don’t need to give this up in the Webworks SDK.

2) When to go for Java SDK and Webworks SDK?

The UI libraries for Java on Blackberry are VERY limited. You will likely have to come up with your own UI framework because what come out of the box is terrible. Doing this is a very large investment of time but will give you total control. The Webworks SDK, on the other hand, offers traditional CSS and HTML support with some decent support for Javascript. This means that creating UI’s will be MUCH easier. My suggestion is to use the Webworks SDK unless you need to develop a game that requires a high-framerate. If you are looking at a data-driven utility or lifestyle application, then the Webworks SDK is the way to go.

3) Both Java and Webworks applications require the latest blackberry OS 5.0? OR whether they are compatible with the lower versions as well?

Java is supported on older models; this has been the case for as long as I can recall; but the Webworks SDK is only available on OS 5 and above. The number of OS 5 devices is a moving target. Many 4.6 devices are on the upgrade path, but as of yet are not running version 5.

4) Whatever developed with Java SDK can be done with Webworks SDK? similarly the vice-versa?

No, there are some types of applications that simply can’t be done via Widgets. Examples are graphics intensive games that require a high frame-rate.

5) Is it possible to create the .java classes for Webworks application development?

Sure, take a look at “Javascript Extensions”. These provide a way to call upon Java code from within Javascript running the Webworks.

6) Whether all the blackberry models supports both Java and Webworks ?

No, only OS 5 and up support Webworks.