As a consultant, I have to move around to various companies as part of my job. Sometimes I am able to stay with the same client for months, sometimes weeks. The one thing that continues to be an issue wherever I go is the availability of a suitable development environment for me to start working on day one. I typically bring in my own laptop so that I can get started as quickly as possible. This is only if the client allows it.
I’ve worked at a number of fortune 500 companies, and typically the answer to the “may I use my own hardware?” question is a solid NO. An exception to that answer was my last client - they are a large company with nearly $19 billion in revenue and yet they have an open policy about outside hardware. They outwardly tell people (at least in the IT areas) that you (employees/consultants) can bring in faster computers and better hardware than we can probably provide. Have at it.
The risk of this position is that of viruses and loss of corporate intellectual property via those personal machines being brought in. The reality of the decision is, it’s not much different than having VPN from home. I, as a developer, need a high quality workstation with lots of RAM. Developing server-based applications requires a lot of resources when testing in a development environment. When asking for a machine less than a year old with 8GB of RAM, I got the typical pushback from desktop support telling me that I shouldn’t be running server applications on a workstation. What? That’s my JOB.
One of my coworkers, a consultant, had been there over a year and already brought in his own monitors and a workstation. I followed suit and brought in my own laptop and monitors. Our productivity skyrocketed having the right equipment for the job. Yes, it’s frustrating not getting the equipment you should expect to do your job. Corporate red tape frequently stifles innovation.
There are positives and negatives for letting people bring in their own hardware. Implement controls to prevent unauthorized connections into corporate file shares and move on is what I say. Think of it this way - you’re paying top dollar to get me in as a consultant. Wouldn’t you want me to be the most effective I can be?
Spring 3.1 brought a lot of good changes to the framework but with any version change, behaviors can be different. Spring does a good job
documenting most of this API changes but there is one that I apparently missed or underestimated the impact of.
Property files can be “imported” into the Spring context so that the values can be inserted into configuration using ${ } with the property
value inside of the brackets. This is a handy feature that I use frequently in my Spring projects. The PropertyPlaceholderConfigurer
has been replaced by PropertySourcesPlaceholderConfigurer in Spring 3.1. One minor difference between them is the latter has the ability
to read @Value annotations for direct injection of property values. The other side effect is that the 3.1 class puts system properties ahead
of your property file’s values. 3.0, on the other hand, let your property file win if a name matched one as a system parameter.
I ran into this problem because my 3.0 configuration had a replacement parameter for a data source name injected by JNDI. The JNDI name
is different between environments at my client, so I had to parameterize it. In Spring 3.0, my configuration was as so:
You’ll notice the context:property-placeholder element has a single properties file. The values read in are:
and they are used in my JNDI configuration:
When I switched to 3.1, I updated the XML namespace to point at 3.1. This changes things behind the scenes to go to PropertySourcesPlaceholderConfigurer.
If you want to retain the original 3.0 behavior, you can keep the XMLNS at 3.0 or add system-properties-mode=”FALLBACK”.
I suspected something was happening with the behavior when I saw in the log files that the data source couldn’t be cast as a string. I
pulled out my hair trying to figure it out and ended up renaming pavDataSource to PavDataSource and it worked fine. This problem came
back up deploying to another environment having the lower case name and I have no ability to change it. Switching back to 3.0 behavior
fixed this because I suspect a system parameter was being created with pavDataSource as the name.
Confusing and frustrating as hell, but the simple mode switch made it right as rain.
Does using Maven with Eclipse make you stabby when you spend an hour waiting for Eclipse to finish validating files? You may not realize
it, but Eclipse is indexing/validating files inside of your project’s target folders! Yes kids, this is annoying and time consuming. The
target folders also end up showing results in the “Open Type” and “Open Resource” windows. I’m sure we’ve all experienced the duplicate
results when searching for a class or resource.
Why does it do this? Eclipse has a feature built in that will, by default, exclude folders that have been marked as “derived”. Normally
folders like your source output folders (bin for example) are marked for you. Well, Eclipse doesn’t automatically mark the target folder as “derived” so it treats it like a regular folder.
Right click your target folder in Eclipse and click the check box for “derived” - magically the folder is now excluded even from the Open
Type and Open Resource windows.
But wait.
Next time you run a Maven “clean”, the target folder is deleted and the check box reset for derived. How do you avoid that? In your
parent project (or current project if you have a single module) add the following to your plugin definitions:
This will force Maven to use version 2.4.1 of the “clean” plugin - if you’re using Maven 3 you can probably remove the version line. After
version 2.3 of the plugin, excludeDefaultDirectories became available. This little gem will only delete the target content and leave the
folder alone for you.
One of the biggest UI no-nos you can perform in iOS is creating a UITextView that assumes the size of the keyboard on the
screen before the keyboard even shows up. You should be dynamically resizing your text views by looking at the dimensions
of the keyboard, and not assuming you know the dimensions.
Why? Try enabling a Japanese keyboard and see how your app performs. You’ll notice that the keyboard is taller than the
English keyboard - it’s to give room to a typeahead area for creating the glyphs. Now how does your app behave?
There is a quick and easy way you can resize automatically. In my example, I have a new view with a nearly full screen-sized
text view showing. When the user taps into the text view, the text view is then resized to leave a bit of gap around it
and the keyboard displays underneath.
The text view without a keyboard
After the user taps in the text view, the keyboard appears. An example of an English keyboard is at left and a Japanese
keyboard at the right. Notice any difference? What should happen is your app just figures out how much space you have
left after the keyboard is displayed and resize accordingly. If you switch between keyboards, you have to account for
visual changes as well. Here is the code I wrote to handle this properly:
-(void)viewWillAppear:(BOOL)animated{[textViewsetText:_notesText];// Register notifications for when the keyboard appears [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotificationobject:nil];[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotificationobject:nil];}-(void)viewWillDisappear:(BOOL)animated{[[NSNotificationCenterdefaultCenter]removeObserver:self];}-(void)keyboardWillShow:(NSNotification*)notification{[selfmoveTextViewForKeyboard:notificationup:YES];}-(void)keyboardWillHide:(NSNotification*)notification{[selfmoveTextViewForKeyboard:notificationup:NO];}-(void)moveTextViewForKeyboard:(NSNotification*)notificationup:(BOOL)up{NSDictionary*userInfo=[notificationuserInfo];NSTimeIntervalanimationDuration;UIViewAnimationCurveanimationCurve;CGRectkeyboardRect;[[userInfoobjectForKey:UIKeyboardAnimationCurveUserInfoKey]getValue:&animationCurve];animationDuration=[[userInfoobjectForKey:UIKeyboardAnimationDurationUserInfoKey]doubleValue];keyboardRect=[[userInfoobjectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue];keyboardRect=[self.viewconvertRect:keyboardRectfromView:nil];[UIViewbeginAnimations:@"ResizeForKeyboard"context:nil];[UIViewsetAnimationDuration:animationDuration];[UIViewsetAnimationCurve:animationCurve];if(up==YES){CGFloatkeyboardTop=keyboardRect.origin.y;CGRectnewTextViewFrame=textView.frame;originalTextViewFrame=textView.frame;newTextViewFrame.size.height=keyboardTop-textView.frame.origin.y-10;textView.frame=newTextViewFrame;}else{// Keyboard is going away (down) - restore original frametextView.frame=originalTextViewFrame;}[UIViewcommitAnimations];}
The view controller adds an observer for when the keyboard shows up and disappears. When the keyboard is coming up, we
record the original frame of the text view - this makes it easier to restore the text view when the keyboard goes away.
In this specific instance, the keyboard cannot be dismissed since enter is set to put carriage returns in the text box.
If you’re looking to get higher frame rates and general application performance tweaks from your iOS application, you
may need to take a look at transparent settings on your subviews. Any time you set a subview to be transparent, the OS
has to blend multiple layers together to figure out the end flattened result. This blending takes CPU cycles and can
impact performance of your app - especially in something as simple as a UITableViewCell.
Luckily there is an easy way to find these problems using Xcode’s companion tool, Instruments.
One of the instrumenting tools you can use on an app deployed to a device is Core Animation. The Core Animation
instrument has a bunch of fancy switches you can flip.
That will turn on a visual indicator to show where multiple transparent layers exist on the screen. For example, the main
table view of my app MigraineDiary shows the following:
To get your app into Instruments, simply select the “Profile” menu item under “Product”. This will build your app and
launch Instruments. Make sure you have your device selected and not the iOS Simulator. Any areas that are heavily colored
in red should be reviewed by you to ensure you’re not setting layers transparent that don’t need to be. This includes
using [UIColor clearColor]!
You’ll notice transparency indicators in red on system components like the tab bar and nav bar. There isn’t much you can
do about these, so you can really just ignore them. If you’ve overridden behaviors, however, you may wish to review your
code to make sure you’re not breaking something.
I’ve moved my blog over from Wordpress to Octopress. I’ve been loving every minute of it. I don’t get the opportunity
to use Ruby and Rails in my daily job. Switching over to Octopress which uses Jekyll for rendering has
a welcome change. Everything now is a static page rather than running on a MySQL database.
Sass and Compass make CSS and HTML so much easier to use. I’ve never been a design
expert although I do use CSS and HTML all the time. This takes the complexity out of making a visually appealing site while conforming to
standards without even having to think about it. Love love love.
I exported all of my Wordpress entries using David Winter’s wordpress-to-jekyll PHP script.
Dead simple and it exported everything as text. None of the images from my previous posts came with, but I can deal with that.
I’ve started to mess around with the Google Data APIs recently to help support
my Migraine Diary iOS application. Specifically I
want users to be able to export their journal entries into a Google Spreadsheet rather than just a plain CSV file. I
am using the Objective-C client that Google built and have come across a number of issues or gotchas.
The Objective-C client is badly documented - a number of Google Data API calls have zero examples and translating REST calls into Objective-C classes is a challenge.
OpenAuth 2 is surprisingly easy to use
Google provides very little troubleshooting assistance even with their client
Objective-C is very new compared to the Python, .NET and Java clients
That being said, I am making progress. I’ll most likely share my finalized code to create a simple spreadsheet here so others have a jumping off point.
I’ve been getting a warning dialog on my Mac (Lion 10.7) when opening Adium. It recently updated to the newest beta and is presenting the following quarantine message every time I open it -
“Adium.app” is an application downloaded from the Internet. Are you sure you want to open it?
Every other time I have gotten the quarantine message, it clears itself after the first launch. This time it did not. I found a quick and easy way to remove the quarantine extended file attribute:
After upgrading my iPhone 4 to iOS 5.0.1, Xcode has been giving me the following error message when debugging my Migraine Diary app remotely:
warning: Unable to read symbols for /Users/aaron/Library/Developer/Xcode/iOS DeviceSupport/5.0.1 (9A405)/Symbols/System/Library/AccessibilityBundles/AccessibilitySettingsLoader.bundle/AccessibilitySettingsLoader (file not found).
warning: No copy of AccessibilitySettingsLoader.bundle/AccessibilitySettingsLoader found locally, reading from memory on remote device. This may slow down the debug session.
I tried deleting the directory and having Xcode pull down the symbols off of the phone again. No success. I ended up copying the contents of the main SDK bundles into the one in my local library. Solved it. Not sure if this is the right solution but it works. I vaguely remember this happening last time Apple released a small point release.
Yes, there are three ways to represent a null value in Objective-C.
NULL = Absence of a value with C-style pointers
nil = Absence of value with Objective-C object variables
NSNull = A nil boxed as an object for storage in a collection
If you try adding nil to a NSDictionary or NSArray, you will find out it doesn’t perform as expected. If you absolutely need to store a null value in a collection, you can use NSNull to represent the lack of a value. For example:
Note, however, that since NSNull represents the lack of a value, there is no way to retrieve that value from the collection. In order to determine if there is no value for a particular key or index, you must compare against NSNull.
id value = [anArray objectAtIndex:3];
if (value == [NSNull null]) {
// Do something for a null
}