Tuesday, December 20, 2011

Flash Pivot Table for Web Applications

Pivot tables are extremely useful for summarizing and analyzing large amounts of data in different ways.  They are most commonly seen in spreadsheet applications such as Excel, but require you to open a file on your computer or share the file via email or a shared drive in order for someone else to see the same reports.  In researching a way to visualize a large set of data with hierarchies of data while at the same time being able to organize the hierarchies in several different ways, I came across a product from flexmonster.com.  They have built a pivot table component using Flex, but not only is it a fully functional pivot table, it also allows you to generate pivot charts instantly.  You can even change the parameters of the pivot table on the fly and load new data if desired.  The component is highly customizable to be able to fit the look and feel of an existing web application.  The documentation is somewhat sparse, but is complete enough when used in conjunction with their trial or demo code to figure out how to get most of what you need from it.

Thursday, October 13, 2011

Using Kiwi with UI Components on iOS

Trying to get unit testing with Kiwi while being able to use UIKit components was beginning to get frustrating.  The issue is that the tests would crash whenever trying to initialize any UIView components such as UILabel, UITextField, etc.  Well, to some the answer may be obvious, but to relative newbies to iOS like myself it was not.  In order to create instances of UI components you need an actual application running(duh?).  When setting up a unit test bundle in Xcode you can either set it up with or without an app that hosts the tests.  Logic tests are done in test bundles that don't have a host app and application tests are done in test bundles that have a host app.  So for those struggling to create tests that rely on UI components, here's how you do it.


Thanks to Allen Ding the creator of Kiwi for his help and pointing me in the right direction.  Happy testing!

Tuesday, October 11, 2011

Creating a Universal Framework from a 3rd Party Framework Project

One of the things I find irritating about development for iOS is when projects are included directly inside of another project or workspace.  Or even the case where they only provide a static library that you must then separately copy the headers into one of your project folders.  Framework packages seem much cleaner.  So I decided to modify the UISpec base project and create targets to output a universal framework that can be included in any other project.  One drawback of this approach though is that whenever the UISpec projects are updated we either have to figure out which files changed and update our own custom UISpec project or re-create the targets to create the universal framework.  In any case, here is how you create a universal framework from the UISpec project in Xcode 4.2 built for iOS 5.

Edit: The content below was modified to be more generic and calls out UISpec specific steps where necessary.

Cleanup Source Control Files (Optional)
--------------------------------------------------
- (optional) Remove all svn or git directories by running 'find . -name ".svn" -exec rm -rf {} \;' or 'find . -name ".git*" -exec rm -rf {} \;' from the base project directory.

Create New Bundle Target for Framework
---------------------------------------------------
- Open the framework project.
- (UISpec specific) Modify specs/main.m.  Remove "@implementation main" and "@end" from the file.
- Rename the static library target to "<Framework Name> Static Library".  ex. rename "UISpec" target to "UISpec Static Library".  This is to allow creation of a bundle target with the name of the framework so that the framework is built as <Framework Name>.framework.
- (UISpec specific) Go to the project level "Build Settings" and change the compiler to "LLVM GCC 4.2".
- Add a new target of type "Bundle" named <Framework Name>.  ex. "UISpec" This will be the framework target.
- Go to the "Build Settings" for the newly created target.
- Change the Base SDK to "iOS 5.0" or whichever version is appropriate for your framework.
- Change "Build Active Architecture Only" to "No".
- Change "Architectures" to "$(ARCHS_STANDARD_32_BIT)".
- Change "Valid Architectures" to "$(ARCHS_STANDARD_32_BIT)".
- (UISpec specific) Change the "Compiler for C/C++/Objective-C" to "LLVM GCC 4.2"
- Change "Dead Code Stripping" to "No".
- Change "Link With Standard Libraries" to "No".
- Change "Mach-O Type" to "Relocatable Object File".
- Change "Wrapper Extension" to "framework".
- Change "Generate Debugger Symbols" to "No".  (project may not always contain this option)
- Go to the "Build Phases" tab.
- Click "Add Phase" and then select "Add Copy Headers".
- In the "Copy Headers" section add the headers from the project as public/private/project headers as appropriate.  Click the "+" button and search for "*.h".  Select all(or appropriate subset because there may be example or other unnecessary files that don't need to be added) then click "Add".  Move the headers up to the appropriate section.
- In the "Compile Sources" section add the source files.  Click the "+" button and search for "*.m".  Select all(or appropriate subset because there may be some example files in the framework project that are not needed) then click "Add".
- Under the "Link Binary With Libraries" section and "Copy Bundle Resources" section, remove all entries.
- Add any necessary imports required by the framework classes to the <Framework Name>-Prefix.pch file.
- (UISpec specific)Under UISpec/SupportingFiles/UISpec-Prefix.pch remove the Cocoa.h entry and add the following entries:
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>

Create Target for Universal Framework
-------------------------------------------------
- Create an "Aggregate" target named "<Framework Name> Universal Framework".
- Update the "Build Settings" by changing "SDKROOT" to "iphoneos".
- Click "Add Build Phase" and then "Add Run Script".  Copy the script below into the script area in "Run Script".  Be sure to update the "FMK_NAME" property to the name of your framework.

# Sets the target folders and the final framework product.
FMK_NAME=UISpec
FMK_VERSION=A

# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework

# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework

# Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator

# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

# Creates and renews the final product folder.
mkdir -p "${INSTALL_DIR}"
mkdir -p "${INSTALL_DIR}/Versions"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers"

# Creates the internal links.
# It MUST uses relative path, otherwise will not work when the folder is copied/moved.
ln -s "${FMK_VERSION}" "${INSTALL_DIR}/Versions/Current"
ln -s "Versions/Current/Headers" "${INSTALL_DIR}/Headers"
ln -s "Versions/Current/Resources" "${INSTALL_DIR}/Resources"
ln -s "Versions/Current/${FMK_NAME}" "${INSTALL_DIR}/${FMK_NAME}"

# Copies the headers and resources files to the final product folder.
cp -R "${DEVICE_DIR}/Headers/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/"

# Removes the binary and header from the resources folder.
rm -r "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/Headers" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/${FMK_NAME}"

# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}"

rm -r "${WRK_DIR}"

Xcode Scheme cleanup
-----------------------------
Since you had renamed the <Framework Name> target and created a new one, you'll probably see <Framework Name> and <Framework Name> 2 as schemes in your project.  Manage your schemes and delete those two schemes.  Then click the "Autocreate" button.  The schemes should now have the updated names.

That's it!  You should be able to build the framework using the new "<Framework Name> Universal Framework" target.  The framework output should be in the base project folder under a directory named "Products".

Wednesday, August 17, 2011

Setting Up WebDAV on Mac OSX Snow Leopard

After trying out several how-to's at various blogs, I finally was able to find one that "almost" worked.  I probably should mention that the first few tutorials I went through would have worked had I not misspelled a directory in the configuration file causing it not to be accessible.  The post below worked except the configuration for the httpd-dav.conf was slightly incorrect.  It shows "Dav On" outside of the <Directory> block, but should be inside the block.  After that everything worked.

http://geekfactor.charrington.com/2009/12/run-a-webdav-server-on-your-mac-to-sync-voodoopad-for-free

The setup that I was trying to achieve is for any user to be able to have read-only access to the WebDAV folders, but requires a valid user(one that is configured in the password file) in order to modify or delete anything.  To accomplish this a couple updates were required in the httpd-dav.conf in /etc/apache2/extras.

1. Add a LimitExcept block in the top level WebDAV directory.
    <LimitExcept GET OPTIONS PROPFIND>
        Require valid-user
    </LimitExcept>

What the above block will do is only allow guests to view the files and directories via a web browser and also connect to the WebDAV directory as a drive/folder.  The LimitExcept block disallows all HTTP command except the ones listed unless the user is valid and authenticated.

2. Add Options for Index

    Options +Indexes
    IndexIgnore ..
    IndexOptions -IconsAreLinks NameWidth=* FancyIndexing SuppressLastModified FoldersFirst
    IndexOrderDefault Ascending Name

The options above allow the files/directories to be seen via a web browser.

Update: WebDAV does not seem to work correctly in Windows 7.  A WebDAV client such as BitKinex is required.

Friday, July 15, 2011

Creating a Struts 2 Project Using Maven on Tomcat With IntelliJ IDEA

This post describes how to create a Java project using Struts 2 as the web framework, Maven as the build system to automatically deploy to Tomcat using IntelliJ IDEA 10 as the IDE.

Setting up Maven:
  • Download the latest version of Maven from http://maven.apache.org/download.html.
  • Install Maven by following the instructions at http://maven.apache.org/download.html#Installation.
Creating a Blank Struts 2 Project Using Maven
  • Change directory to the directory you want the project created in.
  • mvn archetype:generate -B -DgroupId=com.mycompany.myapp -DartifactId=my-app -DarchetypeGroupId=org.apache.struts -DarchetypeArtifactId=struts2-archetype-blank -DarchetypeVersion=<struts version ex. 2.2.3>
Creating the IDEA Project
  • File->New Project
  • Select the option "Create Java project from existing sources".  Then click "Next"
  • Enter a name and location for your project.  Then click "Next" 
  • Select "Do not create source directory" as the source directory was already created by Maven.
  • Click "Next" twice, then "Finish".
Associate Maven Project with IDEA
  • Go to"Maven" in the IDEA preferences.
  • For the Maven home directory value enter the location where you installed Maven ex. /usr/local/apache-maven/apache-maven-3.0.3
  • Click "Maven Projects" on the right side of the IDE.
  • Click  the "+" button to add a new Maven project.
  • Select the pom.xml that was created by Maven.
Add Struts and Dependencies Libraries
  • In IDEA go to the "Project Structure" menu item, click "Libraries" under "Project Settings".
  • Click the button "Attach Classes from Repository".
  • Enter org.apache.struts:struts-core:<struts version> ex. org.apache.struts:struts-core:2.2.3
  • Click "OK".
  • This will add the libraries to a lib folder in your IDEA project.
Add the Mojo Tomcat Deployment Plugin to the pom.xml
  • Add the following code snippet to the plugins section of the pom.xml.
  •             <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>tomcat-maven-plugin</artifactId>
                    <version>1.1</version>
                    <configuration>
                        <url>http://localhost:8080/manager/html</url>
                        <warFile>${project.build.directory}/${project.build.finalName}.war</warFile>
                        <server>tomcat-localhost</server>
                    </configuration>
                </plugin>
  • Note that the url and server values may need to be updated to reflect your installation.
  • In the Maven settings.xml add the following snippet to the "servers" section.
  •     <server>
          <id>tomcat-localhost</id>
          <username>username</username>
          <password>password</password>
        </server>
  • Note that the id must match the server name in the pom.xml and the username/password must be for the user that has the role "manager-gui".
  • To deploy to tomcat, in IDEA under the "Maven Projects" tab you should now see tomcat under "Plugins".  There you can select "tomcat:deploy" or "tomcat:redeploy" to deploy your application.

Monday, July 4, 2011

Drawing in CAShapeLayer versus CALayer

When drawing in a CAShapeLayer you can have a frame that has a width and height of 1 and drawing in the layer outside the frame and bounds will work as long as maskToBounds is not set to YES which is the default.  However, in a CALayer Quartz can only draw within the frame and bounds of the layer.  Stumbled across this when trying to create layers as small as possible to reduce memory usage and noticed that CAShapeLayer's rendered while CALayers did not render a drawing along the same path.

Thursday, June 2, 2011

iOS CALayers

After spending hours using Instruments to find a memory issue where real memory usage was hovering around 170-180MB on an app with many layers I finally was able to pinpoint the cause of the high memory utilization.  The issue was with the size of the CALayer frame's.  The application had about 40 large layers and each was the size of about two-thirds of the screen.  When reducing the size of the frames down to the minimum rectangle needed to display the content at that time, memory usage went down to 40-60MB.  In short, don't make layer frame's larger than absolutely needed. 

Monday, April 11, 2011

Compiling Static Framework for Use in Simulator and on iOS Device

After creating a static framework as described in the previous post it appears that the framework bundle that is viewable in the project pane of Xcode is only for the iphoneos version and not the iphonesimulator version even if the target is specified as the simulator.  Xcode still creates the iphonesimulator version when the simulator target is selected, however it is not viewable in Xcode.  In order to use the simulator version you will need to go to the filesystem.  Go to the same directory as the iphoneos version's parent directory and a directory for the simulator will also be there.  For example, the iphoneos version will be named something like Debug-iphoneos and the simulator will be named something like Debug-iphonesimulator.  Under those directories will be a directory containing your framework named <your product name>.framework, drag and drop that directory into your frameworks group in Xcode to use it.

Friday, April 8, 2011

Creating a Static Framework in Xcode 4

For iOS there is no template in Xcode to build a framework for iOS.  In order to get around this, you can create a Cocoa Static Library project and modify it so that you can develop and compile a static iOS Framework.  Using the post at "http://www.cocoanetics.com/2010/05/making-your-own-iphone-frameworks-in-xcode/" as a basis for writing this tutorial I was able to get it working and used it in a another project by following the steps outlined in this post.  This is the first library I've ever tried to create outside of Java so please feel free to chime in with any comments or corrections.

Create the Xcode project for the framework(skip if you already have an existing project):
- Open Xcode and create a new project (File->New->Project)
- Under the "Framework & Library" section under iOS select "Cocoa Touch Static Library".
- Under "Product Name" enter the name you want to call your framework.
- Click "Next" and "Create".

Add a Bundle target:
- Click the "Add Target" button at the bottom of the Xcode window.
- Select the "Bundle" template under Mac OS X.
- Give it the name of your framework.
- Click "Finish".

Set the Build Settings:
- Change the following properties to the values indicated below...
- Base SDK (replace the value with the appropriate iOS SDK version for your framework).
- Build Active Architecture Only = No
- Architecture and Valid Architectures = $(ARCHS_STANDARD_32_BIT)
- Mac OS X Deployment Target = Compiler Default
- Targeted Device Family (choose the appropriate iOS device i.e. iPhone/iPad)
- Dead Code Stripping = No
- Link With Standard Libraries = No
- Mach-O Type = Relocatable Object File
- Wrapper Extension = framework
- Generate Debug Symbols = No

Modify Info.plist file:
- Under your frameworks "Supporting Files" folder should be a file named <framework>-Info.plist.  Modify the "Bundle OS Type code to "FMWK"

Modify the Prefix.pch file:
- The generated Prefix.pch file under "Supporting Files" contains a reference to the Cocoa framework header file.  Remove that reference from the file.

Remove unnecessary frameworks from your project:
- Under the "Frameworks" folder delete frameworks such as Cocoa.framework and AppKit.framework that your project does not rely on.

Add frameworks required by your framework:
- If the project was created from a Cocoa template, the Cocoa framework is setup by default and not UIKIt which is required for iOS projects.
- Drag and drop any required frameworks such as UIKit under the "Frameworks" folder in your project pane.  In the dialog box that comes up uncheck "Copy items into destination group's folder (if needed)".
- UIKit should be in a folder similar to the following - /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework

Add and develop your framework code files.

Add a new build phase for "Copy Headers":
- Select your framework target.
- Click the "Build Phases" tab.
- Click the "Add Build Phase" button and select "Add Copy Headers" from the pull-down menu.
- Under "Compile Sources" your source files should already be there, if not add them.
- Under "Link Binary With Libraries" remove any frameworks that might be present.
- Under "Copy Headers" add your .h  files to the section with the appropriate scope.  They can be "Public", "Private", or "Project".  You can drag them from the "Project" section to the "Public" or "Private" sections or from the project file pane.

Create Target for Universal Framework
-------------------------------------------------
- Create an "Aggregate" target named "<Framework Name> Universal Framework".
- Update the "Build Settings" by changing "SDKROOT" to "iphoneos".
- Click "Add Build Phase" and then "Add Run Script".  Copy the script below into the script area in "Run Script".  Be sure to update the "FMK_NAME" property to the name of your framework.

# Sets the target folders and the final framework product.
FMK_NAME=MyFramework
FMK_VERSION=A

# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework

# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework

# Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator

# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

# Creates and renews the final product folder.
mkdir -p "${INSTALL_DIR}"
mkdir -p "${INSTALL_DIR}/Versions"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers"

# Creates the internal links.
# It MUST uses relative path, otherwise will not work when the folder is copied/moved.
ln -s "${FMK_VERSION}" "${INSTALL_DIR}/Versions/Current"
ln -s "Versions/Current/Headers" "${INSTALL_DIR}/Headers"
ln -s "Versions/Current/Resources" "${INSTALL_DIR}/Resources"
ln -s "Versions/Current/${FMK_NAME}" "${INSTALL_DIR}/${FMK_NAME}"

# Copies the headers and resources files to the final product folder.
cp -R "${DEVICE_DIR}/Headers/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/"

# Removes the binary and header from the resources folder.
rm -r "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/Headers" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/${FMK_NAME}"

# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}"

rm -r "${WRK_DIR}"

Run the "MyApp Universal Framework" target to build the framework.  The framework bundle should now be under the "Products" folder of your project.  To use it in another project simply drag and drop it from your framework project to a folder in your project.

Hope this was helpful!

Unable to Deploy App to iOS Device

While testing an application on the iPad 2 I experienced several crashes.  All of a sudden I was no longer able to deploy to the device and received the following error in the debugger console within Xcode:

Couldn't register COMPANY.MyApp with the bootstrap server. Error: unknown error code.
This generally means that another instance of this process was already running or is hung in the debugger.warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.1 (8G4)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
(gdb)

Tried restarting the machine running Xcode with no success.  Then tried restarting the iPad which seemed to do the trick.  Pretty standard procedure to try to fix issues that seem to have no apparent reason for occurring.
 

Wednesday, April 6, 2011

Updating Cell Data in UITableView

Today I created a subclass of UITableView which would display a list of RSS feed items.  After creating a custom parser with the necessary callbacks to inform the UITableView subclass after parsing each item and when the feed was finished being parsed, the table needed to be updated to display the RSS items that were pulled from the XML feed.  I struggled with this a bit and tried calling setNeedsDisplay at first thinking that it would cause the view to repaint along with the new data, but that didn't work.  So I hopped onto Google and found that when the underlying data for the table changes a call to the reloadData method on the UITableView instance is required.  After doing this everything worked as expected.  Of course afterwards this all made perfect sense, but these kinds of moments are sure to occur frequently as I learn the iOS frameworks.

Tuesday, March 22, 2011

Learning iOS Development

For those looking to learn developing iOS I'd recommend the following material to help you get started.

If you are not familiar with Objective-C a good book to get you started is "Learning Objective-C 2.0" published by Addison Wesley.

To get familiar with the architecture and ideas behind iOS development definitely read through application programming guide at http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40007072.

An easy to follow and understand first book on iOS specific development is "Beginning iPhone 4 Development - Exploring the iOS SDK" published by Apress.  This book had very complete examples that worked which helped take the frustration out of trying to figure things out whereas some of the other iOS books leave you scratching your head if you don't know what you're doing.

After the above you can go in many directions depending on the type of application you are interested in writing, but those should get you started on the right path.

Update 4/6/2011 - The above books get you familiar with the concepts without going too far into the weeds that you just get lost, but it also means that you sometimes feel left wondering how things really work or connect.  A decent book for learning how things fit together at the code level without Interface Builder is "Advanced iOS 4 Programming" published by Wiley.  Interface builder is not used to encourage better understanding of how the pieces connect which also allows you to code more advanced applications that are not possible using interface builder alone.

WebSphere 7 JSP Java Version Quirk

A couple weeks ago I was working with a client to deploy some web application enhancements to their WebSphere 7 Express server and ran into an unexpected issue.  I had been developing and testing on WebSphere 7 Developer edition which is a full version of WebSphere, but with unlimited use for development.  After numerous deploys and no changes to the default configuration of the server instance I had expected a smooth deployment to WebSphere 7 Express on the client's server.  However, as it turns out the WebSphere 7 Express version defaults to version 13 of Java which is Java 1.3 even though the rest of the server is running on Java 1.6.  In order to change the version of Java for JSP compilation one must choose the detailed deploy and pre-compile JSP option to set the version to a later version otherwise any JSP's developed using features specific to versions above 1.3 will fail to compile and users will see error messages upon page load attempts.  This is just another of many WebSphere 7 quirks I've run into ever since my first experience with WebSphere on version 5.

Up and Running

The corporation is finally up and running with it's own domain, email, website, and more.  Google certainly has a nice set of tools for businesses and individuals to get something up and running quickly and the best part is it's free.  Started this blog as a place to put posts on issues and information related to IT.  Hopefully it will be useful as a reference to the company and others.