Posts tagged: Software

Converting iPhone applications from pay to in app purchases

I have a product on the store called PirateWalla, and based on the nature of the application (More users would probably mean a worse experience for existing users) it was desirable to make it a more premium product (I priced it at 4.99, even though I probably would have made better profit at .99 by selling higher volumes).  The current users of the application are dedicated and active, regularly submitting feedback, asking for new features, and enjoying the app.  However, having a high application cost also meant that whenever a user paid for the application and it wasn’t exactly what they expected they would give it bad reviews.

 

With the new version of this application, I wanted to switch to an in-app purchase model, making the application free to download and try, but charging for the key desired functionality.  However, Apple doesn’t allow you to migrate existing customers to this model very easily.

Can’t just make the switch, because there is no way to give existing customers the new in-app purchase feature for free (App cost = $0 then feature cost will be $4.99 which will work for new customers but existing customers who already bought the app would now have to buy the feature)

Can’t create another application, as it would be confusing to users, and would make it so that there is now two applications to update.

So finally, I’ve decided on a phased upgrade.  First I’ll release the in-app purchase, requiring users to purchase the new functionality at a lower price (.99), while leaving the price of the app the same.  So that existing customers can buy the feature before the price goes up.  Then, once most users have had a chance to upgrade, I’ll drop the apps price to free, and adjust the price of the feature.

I feel bad about taking this route, as it’s not really fair to the existing customers.  So to make up for it, I revamped a whole section of the application, adding new functionality and improving on existing, so that they will be getting something for their .99.

So if you are an existing PirateWalla user, and don’t want to pay me another dime, I understand.  Don’t upgrade past 2.9, and your application will continue to function as normal.

If you’d like the new features and functionality however, please upgrade and buy the “item location” feature as soon as possible, as I won’t leave it at .99 forever.  There are more features to come, and some of them will benefit from having a broader user base (Teaser – Game Center integration, with high scores and achievements!)

Share

When does layoutSubviews get called?

It’s important to optimize any UIView layoutSubviews method you create, as it can be frequently called, and has the potential for creating recursion (triggering a setNeedsLayout from layoutSubviews can create a loop that will grossly affect your apps performance). Layout subviews is called once per run loop on any view that has had setNeedsLayout or setNeedsDisplayWithRect: called on it. So in addition to any time you manually call these methods, it can be useful to know when the UI framework calls setNeedsLayout/setNeedsDisplay as this will trigger layoutSubviews.

For this purpose, I will define a few view relationships:

  • View1 – UIView class, root view for examples
  • View1.1 – UIScrollView class, subview of View1
  • View1.1.1 – UIView class, subview of View1.1 (No autoresize mask)
  • View1.1.2 – UIView class, another subview of View1.1 (Autoresize mask – flexible width)

I then ran the following tests.  An X means the view was layed out

From this I surmise the following:

  • init does not cause layoutSubviews to be called (duh)
  • addSubview causes layoutSubviews to be called on the view being added, the view it’s being added to (target view), and all the subviews of the target view
  • setFrame intelligently calls layoutSubviews on the view having it’s frame set only if the size parameter of the frame is different
  • scrolling a UIScrollView causes layoutSubviews to be called on the scrollView, and it’s superview
  • rotating a device only calls layoutSubview on the parent view (the responding viewControllers primary view)
  • removeFromSuperview – layoutSubviews is called on superview only (not show in table)

Hopefully this is helpful information for you as well.

Share

Blocks Rock – A Cocoa Asynchronous NSURLConnection block example

So I heard that blocks were one of the new features of 4.1 and I decided to give it a try. And it’s awesome! Within half an hour I’d solved a problem that I’d had to make much more complicated implementations to solve previously, and I’m so excited I decided I’d share the code.

Problem: NSURLConnection asynchronous connections are ugly. If you want to have one controller make multiple different calls you have to make unique delegates for each call or have some convoluted way for the connection manager to tell one delegate from another. It’s a real mess.

Solution: BLOCKS!

Step 1: Create NSURLConnection block extension that allows for calling async methods from class API like you would sync method.


//
//  NSURLConnection-block.h
//
//  Created by Kevin Lohman on 9/12/10.
//  Copyright 2010 Logic High Software. All rights reserved.
//  Free to use in your code commercial or otherwise, as long as you leave this comment block in
// http://blog.logichigh.com/2010/09/12/cocoa-blocks/

#import 

@interface NSURLConnection (block)
#pragma mark Class API Extensions
+ (void)asyncRequest:(NSURLRequest *)request success:(void(^)(NSData *,NSURLResponse *))successBlock_ failure:(void(^)(NSData *,NSError *))failureBlock_;
@end

and

#import "NSURLConnection-block.h"

@implementation NSURLConnection (block)

#pragma mark API
+ (void)asyncRequest:(NSURLRequest *)request success:(void(^)(NSData *,NSURLResponse *))successBlock_ failure:(void(^)(NSData *,NSError *))failureBlock_
{
	[NSThread detachNewThreadSelector:@selector(backgroundSync:) toTarget:[NSURLConnection class]
						   withObject:[NSDictionary dictionaryWithObjectsAndKeys:
									   request,@"request",
									   successBlock_,@"success",
									   failureBlock_,@"failure",
									   nil]];
}

#pragma mark Private
+ (void)backgroundSync:(NSDictionary *)dictionary
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	void(^success)(NSData *,NSURLResponse *) = [dictionary objectForKey:@"success"];
	void(^failure)(NSData *,NSError *) = [dictionary objectForKey:@"failure"];
	NSURLRequest *request = [dictionary objectForKey:@"request"];
	NSURLResponse *response = nil;
	NSError *error = nil;
	NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
	if(error)
	{
		failure(data,error);
	}
	else
	{
		success(data,response);
	}
	[pool release];
}

@end

Now just import your new class and make your async call! AWESOME!

	[NSURLConnection asyncRequest:request
						  success:^(NSData *data, NSURLResponse *response) {
							  NSLog(@"Success!");
						  }
						  failure:^(NSData *data, NSError *error) {
							  NSLog(@"Error! %@",[error localizedDescription]);
						  }];
Share

Validating an e-mail address

Question: How do I verify if a string of characters is a valid e-mail address?

First, you can only be sure about the second half of the e-mail address (the domain), as (in order to protect the anonymity of their users) many e-mail servers don’t give immediate responses when checked to see if the first part of the e-mail address is valid (although some will send a bounce notification at a later date, once an e-mail has been attempted).

Second, you can only TRULY verify if the domain address is accurate if the testing application has internet access.

So, without making a DNS call (or before), you can’t be absolutely sure that the user or the domain actually exists, and can never be sure if the user (and therefore the email) is an actual e-mail address.

But you can check to see if the format is valid using a regular expression. And this is where things get REALLY tricky, as how restrictive you want to be in your filtering depends on you, and while there is a defined standard, simply adhering to that standard may exclude e-mail addresses that are in use.

It seems that the most common regular expression that is suggest on the web is the following:

^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$

This will cover ALMOST all e-mail address you will run into, and will exclude obnoxious e-mails like badpirate@gmail.com.nospam

However, it will exclude a few e-mail addresses that are in use (but are probably being excluded and having trouble in lots of places:

  • kevin@yesthistldexists.museum – Yes .museum is a valid Top Level Domain
  • kevin@kevin@logichigh.com – Yes the current e-mail RFC doesn’t allow this type of e-mail address HOWEVER older RFC’s did, and so there may be some folks still using this format (and not being able to use this format in lots of other places)
  • ??@??web.jp – International characters in domains and user names are already being normalized to ascii friendly code by browsers and e-mail clients, so they are being used regularly, however if you are checking before that normalization occurs, these sorts of e-mail addresses will get tossed

Therefore, I’ve also written a super lax e-mail format checker that will catch all scenarios. This reg ex would probably be best used if you plan on checking to see if the domain exists after checking to see if the format loosely matches SOME format that COULD be in use :)

^.+@.+\.[A-Za-z]{2}[A-Za-z]*$

Finally, if you’d like to implement this in cocoa code:

BOOL NSStringIsValidEmail(NSString *checkString)
{
	NString *stricterFilterString = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
	NSString *laxString = @".+@.+\.[A-Za-z]{2}[A-Za-z]*";
	NSString *emailRegex = stricterFilter ? stricterFilterString : laxString;
	NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
	return [emailTest evaluateWithObject:checkString];
}
Share

PirateWalla iPhone

Coming soon!

Arrr… For the truly compulsive GoWalla user.  This here application will perform an ever growing spiral search from your current location and will find any booty (items) you have not collected yet in all nearby locations.  Yarr.. and it can be fine tuned to even help you lower the issue numbers of your existing collected items.
Why would you want to do all of this?  Because you are compulsive.  And gotta have them all.
Why am I charging $5??

  1. This tool is incredibly effective at helping you find rare items.  Rare items that I might also need.  Rare items that other users of the application would just as soon hope that YOU never find.  By making it cost as much as a draft beer, I can assure that only the devoted pirates find the treasure.
  2. The Gowalla API be a shifty one.  Gowalla changes the way their backend works ALL THE TIME, and with NO WARNING.  I could do this application for free… but the upkeep would soon make it not worth the effort to update, and it would be a free broken application.  By charging a few bucks, I can make it worth my time to deal with the GoWalla headache.
  3. I’m a pirate.  Yarr.  Need dub-loons to buy rum.
Share

PirateWalla

I made a tool that should be useful to people who play GoWalla too much.  Currently, it has two functions:

  • GCD – Gowalla Compulsive Disorder – Gives you a score based on how many items you’ve collected and how cool (low number issue) they are.
  • Search Oahu – Searches ALL of Oahu and your friends inventories for items that you need in your collection and tells you where to find them.

Enjoy.

PirateWalla

Share

Malama Card Application

Just finished another iPhone Application, and you can find it in the Apple Store for free starting today!  Start getting great savings around Hawaii using this Malama Card Application built for Kamehameha Schools.  And keep your ears open for more great applications from Logic High Software!


Fast Tube by Casper

Share

Beta Testers Needed

Hey everybody, I’ve got a new geo-location based game coming out very soon that I’d like to beta test a little bit before it’s launch.

Specifically I’m looking for iPhone 2G, 3G and 3GS owners, preferably in the Oahu area as the game is multi-player and depends on having friends to battle with, however if you have a few friends who are also iPhone owners and want to test it out in your area then that is dandy as well.

Sign up for the beta tester mailing list to be a tester

Share

You call that art?

He sat in a poorly lit corner of the furniture crowded coffee house.  His apparel would become outdated if you described it.  Pen in one hand, and a black notebook in the other he bent over his work.

She was at the counter, chatting with the barista, biding her time until she noticed him.  The attraction instant and subconscious.  A primal understanding, here was a mate with talent.  The way young girls swoon over pop stars, or the girl at the bar goes home with the guy that clears the pool table.  She approached the table and sat.

He glanced up from his work, immediately taken in his own way, physically reacting to his own unconscious understanding of her quality.  He felt fueled and inspired by it.  Whether or not he realized it, sitting across from him was the only reason he practiced his art.  His designs the human equivalent of carefully pruned plumage.  He smiled at her, and went back to work, with passion and drive.  He could work the rest of his life sitting across from her, the power of woman so subtle and strong.

She sat and watched him work for a while, without saying a word.  Enraptured in the way he would look up every now and again, making her wonder, is it a portrait?  Or maybe a poem.  Perhaps he’s writing a screenplay.

Is it about me?

“Can I see?”

He clutched the notebook close to his now palipitating chest.  This was his work, what would she think?  It is a big moment, but he has courage and confidence.  He smiles, and pushes the notebook across the table.

She looks at it slowly moving it from side to side.

“What is it?”

Perplexed with a sprig of disappointment she looks to him.

“Code.”

Read more »

Share

Software Blog

I’ve taken the Logic High Software portion of this blog in house so that I can access some of the better features of wordpress.org

All the old posts will remain here, but new posts will be made at http://software.logichigh.com

See you around!

Share

WordPress Themes