Rudifa’s Blog

CloneXcodeProject.sh

Posted in Xcode Tools by rudifa on July 23, 2011

What

Programming with Xcode?

Want to make a fresh start from an existing Xcode project under a new name?

Not quite satisfied with project renaming features in Xcode 4.0?

Me too.

How

I have been using the excellent Monte Ohrt’s script renameXcodeProject.sh for almost 2 years, and I made small improvements along the way.

I named my version of the script cloneXcodeProject.sh to reflect more precisely what the scripts do : while Xcode renames things in place, these scripts make a copy of all project files and then rename the copied files and text items in them.

Sometimes you want to clone a project whose files are read-only (perhaps they were checked into a Perforce depot). In this case the copied files are also read-only, and Monte’s script can’t modify them. My script makes them writable.

Monte’s script refuses to work if the new project name contains the old name. You have to run his script twice in this case, first cloning to a temporary project name and then to the final name, and remove the temporary project at the end. I did this many times, until I looked for and found a simple automated solution.

If needed, my script creates the temporary clone and then launches itself recursively for the second pass in which it clones and then removes the temporary clone.

Here is my script :


#!/bin/sh

################################################################################
#
#      cloneXcodeProject.sh
#
# morphed from the original renameXcodeProject.sh by Monte Ohrt (see below)
# by Rudi Farkas <rudi.farkas@gmail.com>
# version : 1.01
# date : 22 Jul 2011
#
# purpose : copy and rename an XCode project
#
# features (over and above those of renameXcodeProject.sh) :
#
# 1- makes the copied files writable before attempting to modify their content
#
# 2- works even if the new project name contains the old project name, for instance
#     cloneXcodeProject.sh "MyStuff" "MyStuff2"
#
# installation :
#
# copy this file to a directory in your PATH, and make it executable with :
#
#   chmod +x cloneXcodeProject.sh
#
# usage :
#
#   cloneXcodeProject.sh <OldProjectName> <NewProjectName>
#
# example :
#
#   cloneXcodeProject.sh MyStuff MyNewStuff
#
# use at your own risk
# let me know if something does not work as advertized
#
################################################################################

################################################################################
#
# renameXcodeProject.sh
#
# author: Monte Ohrt <monte@ohrt.com>
# date: Jan 27, 2009
# version: 1.0
# http://www.phpinsider.com/xcode/renameXcodeProject.sh.txt
#
# This script will copy an xcode project to a new project directory name
# and replace/rename all files within to work as expected under the new name.
# Project names that contain characters other than alpha-numeric, spaces or
# underscores MAY not work properly with this script. Use at your own risk!
# Be CERTAIN to backup your project(s) before renaming.
#
# One simple rule:
#
# 1) The old project name cannot contain the new project name, so for instance,
#    renaming "MyStuff" to "MyStuff2" will not work. If you really need to do
#    this, rename the project to a temp name, then rename again.
#
# I have instructions for manually renaming an xcode project here:
#
# http://mohrt.blogspot.com/2008/12/renaming-xcode-project.html
#
#
# Installation:
#
# Copy (this) file "renameXcodeProject.sh" to your file system, and invoke:
#
#   chmod 755 renameXcodeProject.sh
#
# to make it executable.
#
# usage:
#
#   renameXcodeProject.sh <OldProjectName> <NewProjectName>
#
# example:
#
#   ./renameXcodeProject.sh MyStuff MyNewStuff
#
################################################################################

OLDNAME=$1
NEWNAME=$2

# remove bad characters
OLDNAME=`echo "${OLDNAME}" | sed -e "s/[^a-zA-Z0-9_ -]//g"`
NEWNAME=`echo "${NEWNAME}" | sed -e "s/[^a-zA-Z0-9_ -]//g"`

echo ${OLDNAME}
echo ${NEWNAME}

TMPFILE=/tmp/xcodeRename.$$
TMPPROJNAME="D401CB997FCB4CB4AABFAC60E754C7B2"

if [ "$OLDNAME" = "" -o "$NEWNAME" = "" ]; then
  echo "usage: $0 <OldProjectName> <NewProjectName>"
  exit
fi

if [ ! -d "${OLDNAME}" ]; then
  echo "ERROR: \"${OLDNAME}\" must be a directory"
  exit
fi

# set new project directory
if [ -d "${NEWNAME}" ]; then
  echo "ERROR: project directory \"${NEWNAME}\" exists. Terminating."
  exit
fi

# does NEWNAME contain OLDNAME ?
echo "${NEWNAME}" | grep "${OLDNAME}" > /dev/null
if [ $? -eq 0 ]; then
  # yes : set up names for the two-pass operation
  FINALNAME="${NEWNAME}"
  NEWNAME="401CB99D-7FCB-4CB4-AABF-AC60E754C7B2"
  echo "Warning: New project name contains old project name. Project will be renamed in two passes."
else
  # no : one pass operation is sufficient
  FINALNAME=""
fi

# be sure tmp file is writable
cp /dev/null ${TMPFILE}
if [ $? -ne 0 ]; then
  echo "tmp file ${TMPFILE} is not writable. Terminating."
  exit
fi

# create project name with unscores for spaces
OLDNAMEUSCORE=`echo "${OLDNAME}" | sed -e "s/ /_/g"`
NEWNAMEUSCORE=`echo "${NEWNAME}" | sed -e "s/ /_/g"`

# copy project directory
echo copying project directory from "${OLDNAME}" to "${NEWNAME}"
cp -rp "${OLDNAME}" "${NEWNAME}"

# remove build directory
echo removing build directory from "${NEWNAME}"
rm -rf "${NEWNAME}/build"

# find text files, replace text
find "${NEWNAME}/." | while read currFile
do
  # find files that are of type text
  file "${currFile}" | grep "text" > /dev/null
  if [ $? -eq 0 ]; then
    # make sure it is writable
    chmod +w "${currFile}"
    # see if old proj name with underscores is in the text
    grep "${OLDNAMEUSCORE}" "${currFile}" > /dev/null
    if [ $? -eq 0 ]; then
      # replace the text with new proj name
      echo replacing "${OLDNAMEUSCORE}" in "${currFile}"
      sed -e "s/${OLDNAMEUSCORE}/${NEWNAMEUSCORE}/g" "${currFile}" > ${TMPFILE}
      mv ${TMPFILE} "${currFile}"
      cp /dev/null ${TMPFILE}
    fi
    # see if old proj name is in the text
    grep "${OLDNAME}" "${currFile}" > /dev/null
    if [ $? -eq 0 ]; then
      # replace the text with new proj name
      echo replacing "${OLDNAME}" in "${currFile}"
      sed -e "s/${OLDNAME}/${NEWNAME}/g" "${currFile}" > ${TMPFILE}
      mv ${TMPFILE} "${currFile}"
      cp /dev/null ${TMPFILE}
    fi
  fi
done

# rename directories with underscores
find "${NEWNAME}/." -type dir | while read currFile
do
  echo "${currFile}" | grep "${OLDNAMEUSCORE}" > /dev/null
  if [ $? -eq 0 ]; then
    MOVETO=`echo "${currFile}" | sed -e "s/${OLDNAMEUSCORE}/${NEWNAMEUSCORE}/g"`
    echo renaming "${currFile}" to "${MOVETO}"
    mv "${currFile}" "${MOVETO}"
  fi
done

# rename directories with spaces
find "${NEWNAME}/." -type dir | while read currFile
do
  echo "${currFile}" | grep "${OLDNAME}" > /dev/null
  if [ $? -eq 0 ]; then
    MOVETO=`echo "${currFile}" | sed -e "s/${OLDNAME}/${NEWNAME}/g"`
    echo renaming "${currFile}" to "${MOVETO}"
    mv "${currFile}" "${MOVETO}"
  fi
done

# rename files with underscores
find "${NEWNAME}/." -type file | while read currFile
do
  echo "${currFile}" | grep "${OLDNAMEUSCORE}" > /dev/null
  if [ $? -eq 0 ]; then
    MOVETO=`echo "${currFile}" | sed -e "s/${OLDNAMEUSCORE}/${NEWNAMEUSCORE}/g"`
    echo renaming "${currFile}" to "${MOVETO}"
    mv "${currFile}" "${MOVETO}"
  fi
done

# rename files with spaces
find "${NEWNAME}/." -type file | while read currFile
do
  echo "${currFile}" | grep "${OLDNAME}" > /dev/null
  if [ $? -eq 0 ]; then
    MOVETO=`echo "${currFile}" | sed -e "s/${OLDNAME}/${NEWNAME}/g"`
    echo renaming "${currFile}" to "${MOVETO}"
    mv "${currFile}" "${MOVETO}"
  fi
done

rm -f ${TMPFILE}

if [ "$FINALNAME" = "" ]; then
  # this is the second pass : remove temp project directory
  if [ "${OLDNAME}" = "${TMPPROJNAME}" ]; then
    rm -rf "${TMPPROJNAME}"
  fi
  echo finished.
  exit
else
  echo
  echo starting the second pass...
  $0 "$NEWNAME" "$FINALNAME"
fi

Why

Googling for “Xcode 4 rename project” produces quite a few discussions and contrasting opinions, for example :

Renaming projects in XCode 4

Xcode – renaming project causes problem

On the Renaming of Xcode Projects

UIButton : setImage:forState vs. setBackgroundImage:forState

Posted in Uncategorized by rudifa on May 6, 2010

The UIButton documentation does not tell you what are the differences between these two methods.
Experimenting uncovers one interesting difference: if you change the button’s frame, background images follow the size change, while images keep their original size.
Take your pick.

Cubz : now I can admit it …

Posted in Uncategorized by rudifa on April 22, 2010

Cubz is available on the AppStore

Posted in Uncategorized by rudifa on April 16, 2010

I submittted Cubz to the AppStore on April 1, it entered into Review on April 4 and was approved for sale on April 5.

However, with my associate we decided to wait a little longer, until the excitement with the iPad calms down a bit, and the world is ready for the next great iPhone app.

Finally, Cubz went live on AppStore today, 16 April 2010.

A small step for a programmer, but a big step for … whatever, someone must have said this a long time ago.

Anyway, I like Cubz, and you will like it too. Promise.

So, now I can sit back and relax, you might say.

Well, no. The future iPad version of Cubz needs a bit of work, in fact quite a lot of work.

Then there’s the i18n (that’s geekspeak for internationalization), Cubz debuts in three languages, and more will follow.

And there are features that did not make it into the V.1.0.

Enjoy Cubz!

The day after

Posted in Uncategorized by rudifa on April 2, 2010

Yesterday, April 1, I submitted my first app to the AppStore for review. What a relief, after weeks of concentration on features, code, bug squashing, internationalizing and all.
Sit back, relax and wait for the email from Apple.

What app, you might ask.

Watch this link to find out.

Tagged with:

iPhone Programming Tricks and Traps

Posted in Uncategorized by rudifa on January 31, 2010

Basic Animation : set the animation properties (like duration) before setting the properties to be animated (this is where the animation is cast in stone).

Example : this fadeOut animation will last 1.5 s, as desired:

-(void) fadeOutMyImage {
 [UIView beginAnimations:nil context:nil];
 [UIView setAnimationDuration:1.5];
 myImageView.alpha = 0.0;
 [UIView commitAnimations];
}

Example : this fadeOut animation will last 0.2 s (the default), not 1.5 s as desired:

-(void) fadeOutMyImage {
 [UIView beginAnimations:nil context:nil];
 myImageView.alpha = 0.0;
 [UIView setAnimationDuration:1.5]; // WRONG, no effect
 [UIView commitAnimations];
}

How to run graphviz on the Mac

Posted in graphviz, OSX by rudifa on January 10, 2010

Install graphviz for Mac from graphviz.org.

To check the installation, open a Terminal and type : dot -h


$ dot -h
dot: option -h unrecognized

Usage: dot [-Vv?] [-(GNE)name=val] [-(KTlso)<val>] <dot files>
...

OK, so dot was installed and added to your $PATH.

Next, create a dot source file and launch dot : dot -T png -O my1st.dot

For example :

digraph d {
 A [label="Hello"]
 B [label="World"]
 C [label="Everyone"]
 A -> { B C }
}

This will create a new file my1st.dot.png that looks like this :

For more about graphviz, look at the gallery and other resources on the graphviz website, or google for more.

OpenTerminalHere with wd in title

Posted in OSX by rudifa on December 18, 2009

How to open a Mac Terminal application from Finder, in its current directory?

Get the app OpenTerminalHere by Marc Liyanage and add its icon in the Finder toolbar. Click on the icon to open a Terminal.

How  to make that Terminal display the working directory in its window title?

Modify the OpenTerminalHere like this :

  1. in Finder, right-click on OpenTerminalHere.app and select Show Package Contents
  2. drill down to OpenTerminalHere.app/Contents/Resources/Scripts and click on main.scpt – this opens the AppleScript editor
  3. just before the line “end process_item” at the end of script insert this line: tell application “Terminal” to set custom title of window 1 to the_path
  4. Compile and Run – it should open a Terminal that displays the path in its title

Bonus: when you right-click on the Terminal’s Dashboard icon, each terminal listed displays the working directory, end of guessing which is which.

How  to make that Terminal display the working directory in its window title? — take two –

As Marc Liyanage, the author of OpenTerminalHere pointed out to me, my change to his script sets the window title at the time of opening the Terminal, but it does not react to subsequent changes of working directory. He suggested putting a suitable ecape sequence into ~/.bashrc. After some man reading and experimenting I settled to the following solution :

  1. Leave the OpenTerminalHere unchanged
  2. Add to ~/.profile

export PROMPT_COMMAND='echo -ne "\033]0; ${PWD}\007"'

This gets executed on every command, and keeps the window title in sync with any change of the working directory.


Tagged with:

Internationalization of my iPhone app

Posted in Uncategorized by rudifa on December 12, 2009

How does the user change the language of the application?

It looks like he can only change the language of the entire iPhone (Settings -> General -> International -> Language).

After the change, an app internationalized for that language will respond in it.

How does the user change the language of the application? – take two -

It turns out that an application can give the user a choice among languages that it supports,

say “en”, “fr”, “de”, “jp”.

When the user selects one of these codes (in the app’s own Select Language menu), the app should do

 [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:languageCode2LetterString, nil] forKey:@"AppleLanguages"];

and instruct the user to stop and to restart the application.

The application will now come up with the newly selected language.

How do I set up an Xcode project for internationalization ?

  • replace strings in the program like
label.text = @"Hello world.";

by

label.text = NSLocalizedString(@"Hello world.",
@"This is a comment about my greeting.");
  • add directories en.lproj, fr.lproj, de.lproj e.t.c.
  • run : genstrings -o en.lproj Classes/*.m
  • add the generated en.lproj/Localizable.strings to Xcode project resources (save as UTF-16!)
  • copy en.lproj/Localizable.strings to fr.lproj/Localizable.strings and edit it to provide translations
  • add fr.lproj/Localizable.strings to project Resources
  • build
  • test

OK, there is more to it but this is a start.

Tagged with:

Profiling an iPhone application with Shark

Posted in Uncategorized by rudifa on September 16, 2009

Here is a quick checklist

  1. Build app and launch on the device
  2. Launch Shark (perhaps from Spotlight)
  3. From the Shark menu, select Sampling->Network/iPhone Profiling
  4. In the Shark window, select the radio button “Control network profiling of shared computers”.
  5. Select your iPhone in the list and optionally configure the profiling session
  6. Check “Use:” next to your iPhone (the checkbox may take several seconds to respond)
  7. Choose the app running on your iPhone from the “Target” drop down.
  8. Press Start to begin profiling, launch the app activity that you wish to profile, press Stop to end profiling
  9. Be patient while Shark transfers the data  to the Mac (this takes longer than the profiling)
  10. In the Time Profile window that Shark opens, select View : Tree (Top-Down)

Tree view provides a very good insight into the percentage of time spent in functions/methods.

Look for those that seem unjustifiably high.

Save the session data for future reference, try to speed up the code and redo the profiling.

Happy hunting!


Follow

Get every new post delivered to your Inbox.