iOS Strategy for multiple device deployment

Thomas McGrath III mcgrath3 at
Sun Feb 13 14:11:36 EST 2011

Well, after two days (except for LiveCodeTV time of course) of testing I have been able to come to some conclusions concerning Orientation methods. The most obvious is that with the way LiveCode does not handle the orientationChanged we have to use resizeStack instead and this way is much slower than other non-LC apps. The best times are 2-3 count via code updating of layout and go card.

Now these are not timed tests because of the way that and Organizer/Console lag with messages and I didn't feel like further delaying this by having to build a logging system. I did test both in the simulator and on the device for each of these tests.

For the sake of these tests I am using my iPhone4 and the latest dev build of LC. I also built just one stack with a card for each orientation for each device for each of two views. The cards are all sized for the iPad in both orientations - 1024 x 1024 with a background group with the Grid layout from the iOS Template Creator V2.0 (rev online is still V1.0)
	iPad Vertical
	iPad Vertical 1
	iPad Horizontal
	iPad Horizontal 1
	iPhoneRetina Vertical
	iPhoneRetina Vertical 1
	iPhoneRetina Horizontal
	iPhoneRetina Horizontal 1

I built a simple interface with a Background grc, rectangle grc set to a border, a button over the rectangle to put a picture in the image, an image, a field with text under the image.

The first TEST was after laying this out on the Vertical card, I copied the controls to the Horizontal card and repositioned everything to look good in that orientation. Then I put this in both cards :
on orientationChanged
	send "updateOrient" to this card in 0 millisecs
end orientationChanged

on updateOrient
put iPhoneDeviceOrientation() into tOrient
if tOrient is "landscape left" then
	put "Hor"
	 go to card "iPhoneRetina Horizontal" in 0 millisecs
	put "Vert"
	go to card "iPhoneRetina Vertical" in 0 milisecs
end if
end updateOrient

This does not work!!! It seems that the only Console logs that show up are from the initial launch of the application for orientationChanged! But the orientationChanged is the only way to change things before the screen is rotated - but it does not seem to work right. resizeStack is handled after the screen is rotated so you see the wrong orient for a second or so before the code changes the view or you see a slight delay depending on which method below that you try.

So I put the code into a resizeStack handler in each card and got more consistent results (count is 1,2,3,4,5 at my average verbal speed):

1. Now in the resizeStack I tried:
go to card "iPhoneRetina Horizontal" 
-- 3-4 count - There is an initial lag of up to 5 count and subsequent lags of up to 3-4 count -- compared to a 1-2 count for other non-LC apps that rotate.
-- BUT now we have two sets of controls with their own code sets which is problematic at best. But the code on each card can be just for that card concerning coordinates etc.

2. I then tried a hidden group with the same controls on the same card:
show grp "Horizontal" 
-- 3-4 count - Initial lag 5 count, subsequent lags 3-4 count
-- Still two sets of controls with two sets of code and more difficult to work with both on the same card with one in a group.

3. I then tried a properties code to get the properties of every control on the card and store them in custom properties:
in a repeat loop
set the xProperty of control Y of this card to the xProperty of btn "Storage" 
--  6-8 count and is noticeably slower. Too many properties are being set that haven't changed using this method.

4. I then tried a duplicate Vertical Card and a duplicate Horizontal card to draw from for just the one card.
put "width,height,loc" into tProperties
in a repeat loop
set the tProperties of control Y of this card to the tProperties of control Y of card "iPhoneRetina Dup Vertical" 
-- 2-4 count - This appears to be just slightly faster if not the same as the "go card" method in 1.
-- Single set of code. Coordinates do change so code needs to be smarter but tweaking is easier with the two extra cards.

5. By carefully capturing the control layout specs this method will be as fast as 4. above with less cards but tweaking is harder since it is all done via code.
-- 2-4 count

Lastly, All of these are extremely slow compared to other non-LC apps when switching orientation on the iPhone. I am going to test these on the iPad today.

-- Tom McGrath III
3mcgrath at

On Feb 12, 2011, at 2:13 PM, Thomas McGrath III wrote:
> I have tried the first two approaches for building a single project for deployment on all available iOS devices. The third is much harder for a visual programmer like myself and as such I have not tried it yet. Your experiences and comments are welcome and appreciated. 
> I uploaded a Utility Stack for this at Rev Online 
> User: Thomas McGrath III 
> Stack: iOS
> Description: iOS Template Creator
> 1.) The first one uses one Stack with multiple cards, one for each device. The stack is sized to the iPad since that is the largest size. For the iPhone3GS/iPhone Retina/iPod the extra space is 'cut off' as it were and seems to work just fine. Then in the preOpenStack use code to determine which device we are launching on and Go to that card. All shared code can be at the stack level and this way seems pretty fast.
> 2.) The second uses one Main Stack with multiple subStacks, one for each device. This way each subStack can be sized to the right device size. Then in the preOpenStack use code to determine which device we are launching on and Go to that subStack. The shared code is harder to deal with (library) since each device has its own stack code and then the main stack also has its stack code as well. But this way is cleaner and if you start with the iPad and get everything organized and coded then it is easier to duplicate the stack and resize it and change the layout for each other device.
> 3.) Use one stack with one card for all devices and orientations. This one is the hardest to both code for and layout. But in the end it is only one card and one stack so it is very clean.
> Now, with both of the first two approaches there are three alternate ways to handle device rotation-orientation.
> A.) The first is by having both orientations available on the same card and via code moving/rearranging the controls to that particular orientation. Having both on the same card requires a lot more coding to handle the layout/rearranging but requires less coding when making changes to the projects functionality - you just have to change the functionality code for controls just once for either orientation.  
> B.) The same as (A) above except but we layout controls so that they can are available for both orientations at the same time. This is easier to show than describe. But if the card is large enough to encompass both orientations then when the device rotates from Vertical to Horizontal the bottom is cut off and the area to the right of the Vertical space is now visible during the Horizontal View and when rotating from Horizontal to Vertical the the right side is cut off and the bottom is now visible. This requires duplicating the controls that are cut off on the right so they are also available on the bottom part so that both are always available regardless of orientation but one or the other is not seen. ( I have a very successful app done in xCode this way and this is actually the easiest way of the three to handle orientation if your layout allows for this. i.e. No pictures or fields will be cut off at the bottom or side.) 
> C.) Or lastly by having two cards per orientation per device (for either (1) single stacks or (2) multiple substacks - above) where the first card is the vertical orientation and the second card is the horizontal orientation. Using two cards, one for each orientation, for each device allows for laying out both orientations ahead of time (good for fine tuning the UI) and requires much less coding to handle the layout but it does require a lot more code when making a change to the functionality - unless all of the code is handled at the stack level and with behaviors (which is preferable anyway). Then when orientation changes just switch cards to that orientation. This requires the most amount of cards etc. but for visual displaying of controls is the best way.
> For the stack One Orientation per Card sizes use:
> iPod  320 x 480 & 480 x 320  -- No Status Bar
> iPod  320 x 460 & 480 x 300  -- Status Bar showing
> iPhone3GS  320 x 480 & 480 x 320  -- No Status Bar
> iPhone3GS  320 x 460 & 480 x 300  -- Status Bar showing
> iPhoneRetina  640 x 960 & 960 x 640  -- No Status Bar
> iPhoneRetina  640 x 920 & 960 x 600  -- Status Bar showing
> iPad  768 x 1024 & 1024 x 768  -- No Status Bar
> iPad  768 x 1004 & 1024 x 748  -- Status Bar showing
> For the stack Two Orientations per Card sizes use:
> iPod  480 x 480 -- Has room at bottom and side for when Status Bar is hidden
> iPhone3GS  480 x 480 -- Has room at bottom and side for when Status Bar is hidden
> iPhoneRetina  960 x 960 -- Has room at bottom and side for when Status Bar is hidden
> iPad  1024 x 1024 -- Has room at bottom and side for when Status Bar is hidden
> For launching to a particular device on startup use:
> on preOpenStack
>    if the environment is "mobile" then
>    iphoneSetAllowedOrientations "Portrait,Portrait Upside Down,Landscape Left,Landscape Right"
>    iphoneUseDeviceResolution "true"
>    end if
> end preOpenStack
> on openStack
>    if the environment is "mobile" then
>    processTheDevice
>    end if	
> end openStack
> on processTheDevice
>    put the machine into tDevice
>    switch tDevice
>        case "iPhone Simulator"
>        case "iPhone"
>            if iphoneDeviceScale() is 2 then -- iPhone Retina
>                if the cShowStatusBar of this stack is true then
>                    iphoneShowStatusBar -- 40 difference
>                else
>                    iphoneHideStatusBar
>                end if
>               go card "iPhone"
>               -- go stack "iPhone"
>            else -- iPhone 3GS
>                if the cShowStatusBar of this stack is true then
>                    iphoneShowStatusBar -- 20 difference
>                else
>                    iphoneHideStatusBar
>                end if
>              go card "iPhone3GS"
>               -- go stack "iPhone3GS"
>            end if
>            break
>        case "iPad Simulator"
>        case "iPad"
>            if the cShowStatusBar of this stack is true then
>                iphoneShowStatusBar -- 20 difference
>            else
>                iphoneHideStatusBar
>            end if
>            go card "iPad"
>            -- go stack "iPad"
>            break
>        default
>            iphoneShowStatusBar
>            go card "iPod"
>            -- go stack "iPod"
>    end switch
> end processTheDevice
> -- Tom McGrath III
> 3mcgrath at

More information about the use-livecode mailing list