Friday, September 3, 2010

How to calculate Easter Day in iPhone OS

Recently, I have to implement the calculation of Easter Day.

Here is what I got

Easter Day is always the Sunday after the full moon that occurs after the spring equinox on March 21. This full moon may happen on any date between March 21 and April 18 inclusive. If the full moon falls on a Sunday, Easter Day if the Sunday following. But Easter Day cannot be earlier than March 22 or later than April 25.

To find the the full moon day, I have used the NSChineseCalendar in iOS 4.

and my implementation is here
eastercal.m Select all

// eastercal.m
#import <Foundation/Foundation.h>
#include <stdio.h>

int main( int argc, char *argv[] )
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSDate *today = [NSDate date]; // today
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger unitFlags = NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit;
NSDateComponents *gregorianComps = [gregorian components:unitFlags fromDate:today];
if (argc==2) {
[gregorianComps setYear:atoi(argv[1])];
}
[gregorianComps setDay:21];
[gregorianComps setMonth:3];
NSDate *easterStartDate = [gregorian dateFromComponents:gregorianComps]; //March 21 for the year

NSCalendar *chinese = [[NSCalendar alloc] initWithCalendarIdentifier:NSChineseCalendar];
// convert from gregorian calendar to chinese calendar
NSDateComponents *chineseComps = [chinese components:unitFlags fromDate:easterStartDate];
NSDate *easterStartDateChineseDate = [chinese dateFromComponents:chineseComps];

NSDate *easterStartDateChineseDateTemp = easterStartDateChineseDate;
if ([chineseComps day] >=15) { // 15 is the full month day in Chinese Calendar
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setMonth:1]; // set the next month
easterStartDateChineseDateTemp = [chinese dateByAddingComponents:offsetComponents toDate:easterStartDateChineseDate options:0];
}
NSDateComponents *dayComponents = [chinese components:NSDayCalendarUnit fromDate:easterStartDateChineseDateTemp];
NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
[componentsToAdd setDay: (15 - [dayComponents day])];
// find the next full month date
NSDate *springEquinoChineseDate = [chinese dateByAddingComponents:componentsToAdd toDate:easterStartDateChineseDateTemp options:0];

NSDateComponents *springEquinoChineseComps = [chinese components:unitFlags fromDate:springEquinoChineseDate];


NSDateComponents *diffComps = [chinese components:NSDayCalendarUnit fromDate:easterStartDateChineseDate toDate:springEquinoChineseDate options:0];
NSInteger diffDays = [diffComps day];

// calculate the days difference from the March 21 to the next full month day
NSLog(@"diffDays is %ld",diffDays);

NSDateComponents *daysToAdd = [[NSDateComponents alloc] init];
[daysToAdd setDay:diffDays];
NSDate *springEquinoGregorianDate = [gregorian dateByAddingComponents:daysToAdd toDate:easterStartDate options:0];

// convert the next full month date from ChineseDate to GregorianComps
NSDateComponents *springEquinoGregorianComps = [gregorian components:unitFlags fromDate:springEquinoGregorianDate];

NSLog(@"springEquinoGregorian is %ld %ld %ld",[springEquinoGregorianComps year], [springEquinoGregorianComps month], [springEquinoGregorianComps day]);

int weekday = [springEquinoGregorianComps weekday];
NSDate *easterSundayGregorianDateTemp = springEquinoGregorianDate;
NSDateComponents *offsetGregorianComponents = [[NSDateComponents alloc] init];
if (weekday == 7) {
[offsetGregorianComponents setWeek:2]; // If the full moon falls on a Sunday, Easter Day if the Sunday following
}
else {
[offsetGregorianComponents setWeek:1];
}
easterSundayGregorianDateTemp = [gregorian dateByAddingComponents:offsetGregorianComponents toDate:springEquinoGregorianDate options:0];
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:easterSundayGregorianDateTemp];
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
[componentsToSubtract setDay: 0 - ([weekdayComponents weekday] - 1)];
NSDate *easterDate = [gregorian dateByAddingComponents:componentsToSubtract toDate:easterSundayGregorianDateTemp options:0];

NSDateComponents *easterComps = [gregorian components:unitFlags fromDate:easterDate];
NSLog(@"Easter Date is %d %d %d",[easterComps year], [easterComps month], [easterComps day]);
[pool drain];
return 0;
}



This code does not run on Mac OS 10.5 or iOS 3 as the ChineseCalendar was not implemented.
It will only run on Mac OS 10.6 or iOS 4


iPhone-4:root# gcc -I/var/toolchain/sys30/usr/include -F/var/toolchain/sys30/System/Library/Frameworks -L/var/toolchain/sys30/usr/lib -framework Foundation eastercal.m -o eastercal
iPhone-4:root# ldid -S eastercal
iPhone-4:root# ./eastercal 2011
eastercal[3005:107] diffDays is 27
eastercal[3005:107] springEquinoGregorian is 2011 4 17
eastercal[3005:107] Easter Date is 2011 4 24

.
.
.

Wednesday, June 16, 2010

iphone.org.hk/apt/ is down

Please update the cydia source url

http://cydia.iphone.org.hk/apt/


.
.
.

Tuesday, June 8, 2010

Sign up for iAd

Here in iTunes Connect -> Contracts

Monday, June 7, 2010

iPhone gcc for SDK 3.2 & iPad

iPhone gcc for SDK 3.2
(1) Install iphone gcc installed in your jailbroken iPad with firmware 3.2

iPhone gcc is available in Cydia. To install it in you need to do these


# assume you have installed APT 0.6 Transitional and Aptitude and wget in Cydia, so that you can use the command apt-get
# if libgcc is broken in Cydia, you have to install it manually before iphone-gcc
wget http://apt.saurik.com/debs/libgcc_4.2-20080410-1-6_iphoneos-arm.deb
dpkg -i libgcc_4.2-20080410-1-6_iphoneos-arm.deb
# install iphone-gcc
apt-get install iphone-gcc


Moreover, install these utilities via apt-get as well


apt-get install make ldid zip unzip wget


for editor in iPad you could use vim or nano

(2) Header files for toolchain and SDK 3.2

the header files for SDK 3.2 is available in one zipped tar file (sys32.tgz). You can download it (about 147M) here

(3) copy and untar the required headers and libraries (first copy to /var/mobile/sys32.tgz) and install it in iPad say

mkdir -p /var/toolchain/
cd /var/toolchain/
tar -xzvf /var/mobile/sys32.tgz


(4) Use this sample TabBarSample.zip and unzip it to test.

This TabBar sample source code is compatible with iPad and iPhone gcc, with auto-rotation and auto-resizing support.

http://apiexplorer.googlecode.com/files/TabBarSample.zip

wget http://apiexplorer.googlecode.com/files/TabBarSample.zip
unzip TabBarSample.zip
cd TabBarSample
make install





The package includes a new command line utility called appinstall, it is used to install compiled app to /var/mobile/Applications/* directory for iPad, it simulates the app install process via XCode.
.
.
.

Sunday, April 18, 2010

MFMessageComposeViewController Sample Code (OS 4.0 only)

Start a new View-based Application Project called SMS2
and have to add the MessageUI framework to the project

Modify SMS2ViewController.h

  SMS2ViewController.h    Select all

// SMS2ViewController.h
// SMS2

#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import <MessageUI/MFMessageComposeViewController.h>

@interface SMS2ViewController : UIViewController <MFMessageComposeViewControllerDelegate> {
UILabel *message;
}

@property (nonatomic, retain) UILabel *message;

-(void)displayComposerSheet;

@end


and in SMS2ViewController.m

  SMS2ViewController.m    Select all

// SMS2ViewController.m
// SMS2

#import "SMS2ViewController.h"

@implementation SMS2ViewController
@synthesize message;

/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/


// Implement loadView to create a view hierarchy programmatically, without using a nib.
/*
- (void)loadView {

}
*/

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *smsButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
smsButton.frame = CGRectMake(97.0, 301.0, 125.0, 37.0);
smsButton.adjustsImageWhenDisabled = YES;

[smsButton setTitle:@" Send SMS" forState:UIControlStateNormal];
[smsButton setTitleColor:[UIColor colorWithWhite:0.000 alpha:1.000] forState:UIControlStateNormal];
[smsButton setTitleShadowColor:[UIColor colorWithWhite:0.000 alpha:1.000] forState:UIControlStateNormal];
[smsButton addTarget:self action:@selector(displayComposerSheet) forControlEvents:UIControlEventTouchUpInside];

message = [[UILabel alloc] initWithFrame:CGRectMake(20.0, 360.0, 280.0, 29.0)];
message.frame = CGRectMake(20.0, 360.0, 280.0, 29.0);
message.adjustsFontSizeToFitWidth = YES;
message.hidden = YES;
message.text = @"";
message.userInteractionEnabled = NO;

[self.view addSubview:smsButton];
[self.view addSubview:message];
}


-(void)displayComposerSheet
{
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
picker.messageComposeDelegate = self;

picker.recipients = [NSArray arrayWithObject:@"123456789"]; // your recipient number or self for testing
picker.body = @"test from OS4";

[self presentModalViewController:picker animated:YES];
[picker release];
NSLog(@"SMS fired");
}

- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
message.hidden = NO;
switch (result)
{
case MessageComposeResultCancelled:
message.text = @"Result: canceled";
NSLog(@"Result: canceled");
break;
case MessageComposeResultSent:
message.text = @"Result: sent";
NSLog(@"Result: sent");
break;
case MessageComposeResultFailed:
message.text = @"Result: failed";
NSLog(@"Result: failed");
break;
default:
message.text = @"Result: not sent";
NSLog(@"Result: not sent");
break;
}

[self dismissModalViewControllerAnimated:YES];

}

// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}

- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}


- (void)dealloc {
[super dealloc];
}

@end




.
.

Saturday, April 17, 2010

Enable Homescreen Wallpaper in iPhone Simulator OS 4.0 beta 1

Edit this file (you need root access

/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.0.sdk/System/Library/CoreServices/SpringBoard.app/simulator.plist

and add the key as below
"homescreen-wallpaper" = 1;



The default HomeBackground.jpg and LockBackground.jpg are here
/Users/yourusername/Library/Application Support/iPhone Simulator/4.0/Library/SpringBoard/


As a bonus, if you add this homescreen-wallpaper key-pair, the problem of "iPhone simulator goes black when trying to taking app to background" problem will be solved.

.
.
.