Wednesday, April 29, 2009

Wow! Look at these prizes

Damn it, I might miss this compitition.

Apple Desing Awards

Great Software Deserves Great Prizes
Winners will receive two 15-inch MacBook Pros (best configuration), two 30-inch Apple Cinema Displays, two 16GB iPhone 3Gs, two 16GB iPod touch, an ADC 2009 Premier Membership, and reimbursement of their WWDC 2009 E-ticket.

Student category winners will receive one 15-inch MacBook Pro, one 30-inch Apple Cinema Display, one 16GB iPod touch, one 8GB iPhone 3G, one ADC 2009 Student Membership, and reimbursement of their WWDC 2009 E-ticket.

Entries will be accepted beginning Thursday, April 2 and ending at 5PM (PST) Monday, May 4, 2009.


OK... Hope for the next time. I am pretty sure Apple will run this next time.

What could error code 560030580 means?

When Apple use the error enumerations, it used a fancy cool tip to define the error code. (I would like to call this magic error number, whatever apple call it.)

Just look at this:

kAudioFormatUnsupportedDataFormatError 1718449215 = ‘fmt?’
The playback data format is unsupported (declared in AudioFormat.h).
Available in iPhone OS 2.0 and later.


When you run you app and get an error code, the only thing you could see in the console is an error number like 1718449215 or 560030580, if you don't know what this magic number is, you would have no idea what this f**king number is. But if you paste this number to calculator app(I mean the system calculator application as below), you would see the real meaning in these number.

[caption id="attachment_259" align="aligncenter" width="362" caption="Paste the magic error number and see the real meaning"]Paste the magic error number and see the real meaning[/caption]

Did you see? in the left down corner, there is an string "!act" that's what this number means.

The main idea behind this magic error number is how to interpret the 4 bytes int32 data type. When we define a number in C or in C++ and Obj-C, you can say:

Int32 a = 'abcd';


This is legal and cool, it gives every number an abbreviated meaning.

Well, Frankly, it is a good tip! But the nightmare is Apple did not use it everywhere, it just adopted some of these mechanism into the current iPhone API, especially, in CoreAudio, so if you find some error code is strange, just copy it, paste it to the calculator, see what you can get. It might be help.

Tuesday, April 28, 2009

I am at Twitter now!

OK, I admit that I've been out of the time for a while, now, I am back with twitter!


[caption id="attachment_254" align="alignleft" width="300" caption="Wow~~, me!"]Wow~~, me![/caption]Twitter me Now!

Sunday, April 19, 2009

What a real swipe should be?

What a real swipe should be ?

Before we get the correct answer, let see what Apple’s engineer told us to do. Look at this video[Matt Drance:Advanced UIKit and Device Features@iPhone Tech Talk World Tour] and seek for 47:15 and you will see, Matt Drance told us to do like this:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    // “start” is an instance variable
    start = [[touches anyObject] locationInView:self];
}

//Slide sub-title: Analyze direction and speed

//-------------------------

#define HORIZ_DRAG_MIN 12

#define VERT_DRAG_MAX 4

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint current = [[touches anyObject] locationInView:self];
    float deltaX = fabsf(current.x - start.x);
    float deltaY = fabsf(current.y - start.y);

    if ( deltaX >= HORIZ_DRAG_MIN  && deltaY <= VERT_DRAG_MAX)
    {

        // it’s a swipe
    }
    else
    {
        // it’s not a swipe
    }

OK, I have to say, when you first read this, it did sound reasonable to determine a serials touch events to be a swipe or not. But when you really test it, you will see, you are missing a serious scenario:

Touch Down –> Move to the right –> then Move to the left quickly(You even don’t need to be so quick.)

Or, you can do it vice versa. You will only get the swipe right result. That’s not we really wanted, didn’t we?

The problem lies in how we determine the swipe action. If you test the above scenario in UITableView which is automatically taking care of swipe for us, you will see the UITableView works pretty fine. When you move to the back direction, it does move the table view to the correction direction as we wanted. That means we haven’t caught the right swipe events. So, where is the problem? The problem is Matt was wrong, or at least he did not tell us the full image of a swipe event.

He did write that we need to analyze the direction and speed. The solution to this is analyze the speed between the current movement and the movement just happened right before current one.

As a conclusion, you need to use:

     moveSpeed = fabsf(deltaX / deltaTime);

Where deltaTime is the subtraction of 2 timestamp of 2 movement event. When this speed is over 100 pixels/second, you will can say, this is a swipe action. (100pixel/s is my judgment, you might choose higher or lower speed.)

 

Here is the full story.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    // Record the start point
    theSecondLastPosition = [touch locationInView:self];
    theSecondLastTime = touch.timestamp;
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint currentTouchPosition = [touch locationInView:self];
    float deltaX = currentTouchPosition.x - theSecondLastPosition.x;
    float deltaY = currentTouchPosition.y - theSecondLastPosition.y;
    moveSpeed = fabsf(deltaX / (touch.timestamp - theSecondLastTime));

    // If the touch event falls into following pattern, it appears to be a swipe
    if ( moveSpeed >= SWIPE_SPEED)
    {
        if (theSecondLastPosition.x < currentTouchPosition.x){
            swipeType = SWIPE_RIGHT;
        }
        else{
            swipeType = SWIPE_LEFT;
        }
    }
    else
    {
        // Process a non-swipe event.
        swipeType = NOT_A_SWIPE;
    }

    theSecondLastPosition = [touch locationInView:self];
    theSecondLastTime = touch.timestamp;
}

Wow~~~, enjoy your new swipe events!

Saturday, April 18, 2009

More about AudioUnitSetParameter

Apple release iPhone SDK based on Mac OS 10.5, and they used a lot of concept which is used in Mac OS directly in iPhone development. But to tell the truth, even the Mac development documentation is still lack of a lot of details, so Apple just leave those jungles directly to iPhone developers. Today, let talk about AudioUnit and the parameters.

AudioUnit is a good library, it provides a lot of predefined processes for us to deal with the audio data. But I have to say, Apple, you really leave a huge jungle in AudioUnit. You can almost find no useful documents for you to understand the APIs. If you want to use an AudioUnit, you do need to invoke a lot of function in a certain sequence. Otherwise, the AudioUnit will refuse to work.

After you properly set up the AudioUnits and AUGraph, you still might be confused when you want to just some properties of a AudioUnit on the fly, you will find out that you are falling into another jungle. You will hard to know which parameter to use and how to use it. Because All you can access the parameters of an AudioUnit is AudioUnitSetParameter. If you look into this API's document, you will see what the real jungle is:

AudioUnitSetParameter
Sets the value of an audio unit parameter.

OSStatus AudioUnitSetParameter (
AudioUnit inUnit,
AudioUnitParameterID inID,
AudioUnitScope inScope,
AudioUnitElement inElement,
AudioUnitParameterValue inValue,
UInt32 inBufferOffsetInFrames
);

Parameters
inUnit
The audio unit that you want to set a parameter value for.

inID
The audio unit parameter identifier.

inScope
The audio unit scope for the parameter.

inElement
The audio unit element for the parameter.

inValue
The value that you want to apply to the parameter.

inBufferOffsetInFrames
Set this to 0. To schedule the setting of a parameter value, use the AudioUnitScheduleParameters function.

Return Value
A result code.

Availability
Available in iPhone OS 2.0 and later.
See Also
AudioUnitGetParameter
AudioUnitScheduleParameters
Declared In
AUComponent.h


See, the first parameter is easy to understand, it means which AudioUnit you want to set/change a parameter with.
the second one will be a little confused, because you need to find out each AudioUnit has which kind of parameters at all. Well, to tell the truth, if you don't know a parameter name, there is no way for you to jump to the parameters defination! So, here is what might be help to you. [Click Here(Local help URL, if you don't have iPhone SDK documentations installed in your system, don't click this URL)]. And don't forget to bookmark it! ;-p

Friday, April 17, 2009

A “Retain” Trap

I just met a weird problem when using UIButton to create a customized button. The object will be released automatically even I stated a property with retain.

Before I merged this code to my main development version, I tested and run it on a test project and it worked pretty fine.

UIBUtton *myButton;

@property(nonatomic, retain) UIButton *myButton;

then I created this button:

myButton = [UIButton buttonWithType:UIButtonTypeCustom];

and used this button in another method(message):

myButton.frame = …;

When I set the myButton.frame property, it always return “EXC_BAD_ACCESS”, or some weird “Selector is not found on UILayer…” blah blah…

While this snippet worked fine in my test program. After some quick investigation, the problem lies on how we maintain the object after we create it. buttonWithType is a static method for UIButton, so any object created by static method will be added to the auto-release pool, and when this object will be released will be unpredictable. Even we had stated the UIButton as a property which has the retain property, it still need to do the retain by our own hand. Like this:

myButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];

Wow, it works fine now.