Sh*t my brain says and forgets about

Category: Uncategorized Page 26 of 30

Bringing in your own hardware to work

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’s PropertyPlaceholderConfigurer

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:

[gist 1855160]

You’ll notice the context:property-placeholder element has a single properties file. The values read in are:

[gist 1855426]

and they are used in my JNDI configuration:

[gist 1855169]

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”.

[gist 1855156]

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.

[gist 1855239]

Confusing and frustrating as hell, but the simple mode switch made it right as rain.

Maven & Eclipse target folder + validation stabbyness

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:

[gist id=1801819]

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.

Enjoy!

Resizing a UITextView automatically with the keyboard

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

blanktextview

standardkeyboard
japanesekeyboard

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 {
[textView setText:_notesText];

// Register notifications for when the keyboard appears
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)keyboardWillShow:(NSNotification*)notification {
[self moveTextViewForKeyboard:notification up:YES];
}

- (void)keyboardWillHide:(NSNotification*)notification {
[self moveTextViewForKeyboard:notification up:NO];
}

- (void)moveTextViewForKeyboard:(NSNotification*)notification up:(BOOL)up {
NSDictionary *userInfo = [notification userInfo];
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardRect;

[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
animationDuration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
keyboardRect = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];

[UIView beginAnimations:@"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];

if (up == YES) {
CGFloat keyboardTop = keyboardRect.origin.y;
CGRect newTextViewFrame = 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 frame
textView.frame = originalTextViewFrame;
}

[UIView commitAnimations];
}

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.

Fixing Layer Transparency Issues in Xcode

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.

coreanimation

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:

screenshotwithouttransparenciesscreenshotwithtransparencies

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.

Google Data API

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.

Adium always presenting Apple Quarantine Message

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:

sudo xattr -d -r com.apple.quarantine /Applications/Adium.app

Relaunch Adium one more time with the “first time you’ve opened” warning and you’re set!

Missing AccessibilitySettingsLoader bundle with iOS 5.0.1 debugging

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.

So copy the following directory:

/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/System/Library/AccessibilityBundles

to:

/Users/[your login name]/Library/Developer/Xcode/iOS DeviceSupport/5.0.1 (9A405)/Symbols/System/Library/

iOS Basics: nil vs NULL vs NSNull

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:

NSNull nullValue = [NSNull null];
[anArray addObject:nullValue];

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
}

iOS – Customize Table View Cells

Ever wanted to have alternated colors on your table view cells? If so, you’ve probably done something inside of cellForRowAtIndexPath and applied a background color to your cell there.

Would you be surprised to know that’s completely wrong?  Yup.  Wrong.  WRONG WRONG WRONG.

I didn’t know this, but any styles applied to cells based on state or whatever should really be in willDisplayCell – NOT when you configure the cell itself!  Per Apple’s documentation for the Table View delegate –

“A table view sends this message to its delegate just before it uses cell to draw a row, thereby permitting the delegate to customize the cell object before it is displayed. This method gives the delegate a chance to override state-based properties set earlier by the table view, such as selection and background color. After the delegate returns, the table view sets only the alpha and frame properties, and then only when animating rows as they slide in or out.”

Keep this in mind especially if you’re using a NSFetchedResultsController with CoreData.  You’ll have to issue a [tableView reloadRowsAtIndexPaths:…] in your didChangeObject method.  For some reason, at least in iOS 4.3.3, the willDisplayCell isn’t firing with the default code Apple recommends when using a Fetched Results Controller.  Adding that reload does the trick.

Page 26 of 30

Powered by WordPress & Theme by Anders Norén