The LION has arrived, and is being installed on millions of devices around the world. Or, so it would seem based on how long it took to download the 3+ Gigabyte latest version of Apple’s OSX operating system. And at the reduced (by $100 from the last update) price of $30, I imagine it’s going to fly off the virtual shelves. I say that because, for the first time, there are NO CD install options (or so said Apple during WWDC 2011). Watch that long but informative video here:
Before I ramble on about some of my favorite features, it’s important to point out that this upgraded is not for everyone. Slower Code 2 Duo systems will see a little slowdown in how things run. Even on my early Core 2 Duo system with a measly 2GB of memory, it’s not much more than an occasional annoyance when things load. Once everything is up and running, I don’t see any performance hit. The new version is also limited to certain processor classes, so unless you have one of these processors, the installation instructions say you won’t be able to enjoy the latest:
Supported Processors
Core 2 Duo
i3
i5
i7
Once you download the software, it took about 40 minutes to complete the installation. It’s a hands-off install (I ran mine overnight) once you have it started. You can walk away, come back about 1 hour later and you are ready to go. No nasty multiple restarts and driver re-installs or trash like that.
By now, you might be wondering, or saying out loud “So what? How do I buy this supposedly great upgrade?!?”. It’s not a single step operation, but overall all it’s pretty simple.
The first thing you will need to do is run the Software Update:
This will upgrade your Apple App Store (seen down there in the taskbar, this is not the same thing as your Apple iTunes App store for handheld devices).
From there, you will easily find the LION product you can purchase.
If you have not yet purchased it under your Apple ID, then you will be offered the product at around $30. Now, here is the part that I really like, if you have already purchased the upgrade (such as me), you don’t have to pay for it again, to install it on another device that you own, and have linked to your Apple ID! This is fantastic! Not only is it very inexpensive, the installation process is designed to work well for families and people with multiple systems. Something a competitor might learn something from…. (although I’m sure they would screw it up 1000-way to Sunday, LOL).
Once installed, you are flooded with 250 NEW features in the latest incarnation of OSX. That’s not 250 enhancements, that 250 NEW Features! Wow. So, what are those features? I’m not going to list all 250. I’m not even going to spend much time trying to describe them myself, so I’ll direct you do the Apple website, and you can pick the ones YOU are interested in:
[details] I like to keep the items I run often in my taskbar, but there is not room to keep everything I might ever run there. When I want to go find some seldom used app, I used to have to use the Finder, open Applications and poke through list. NOT ANY MORE! With a simple 4-finger swipe on the track pad (or clicking that rocket icon you might have noticed in my screen shot above) you are given an iOS (that’s iPhone/iPad/iPod style interface for the techno-neophytes that are now lost). ALL of the apps are there. If you have too many to fit on one page, well, you just swap left and right, find what you want an LAUNCH! It’s a really cool feature!
You can see that Apps in sub-directories are presented in the same method as they are on the iOS OS. When Apple said they took usability lessons from iOS and brought them to LION, it was much more than just some marketing hype. It’s real, and it works.
Mission Control
[details] Spaces has been changed too, and now it’s Mission Control. Like multiple desktops (like me) then you can access, add, remove them with a simple 3-finger up-swipe to see all your desktops:
It’s easy to move running apps from space to space too, and you might notice the dashboard is the first desktop on the right, so you can get there using spaces. So, why is that cool? Well, to shift from space to space it’s a simple matter of a 3-finger swipe left or right to access the space you want. Again, it’s just that simple!
Autosave
[details] This is such an awesome, intelligent, useful feature. Gone are the days of you cursing because you forgot to save a document, and for some reason the application closed, maybe because you restarted and forgot it was open (although the OS will remind you), or the system crashed (I’ve NEVER had my MAC crash.. EVER), or you simple hit the wrong button and didn’t save! OH NO. Well, this has you covered. Gone are the annoying popups (do you want to save?), because it will save it for you, when you need it to. Combined with Versions.. you have a very secure and safe environment in which to create, anything.
Versions
[details] And it will save different versions of your document AS YOU EDIT, so you can revert back to a previous state at any time. If you are familiar with time machine, you’ll understand how it works. I don’t have a demo to show you on my computer (yet) but I’ve tested it on another. This is one you want to read about for sure!
Having used the new OS for only 24 hours how, I’ve just scratched the surface of the new capabilities. I will say with complete confidence, I am glad that I upgraded, I’m using the Launch Pad and Mission Control heavily already.
Wow.. talk about a learning curve. The new iOS SDK 4.x (new to me, have not been writing iPhone apps much this year) is a radical change from the version I learned with.
I don’t doubt that I’ll find my around and start re-compiling my code with the new SDK for both iOS4 and iOS5 soon, but right now, I’m stalled trying to do something pretty simple like adding a 3rd view to the Tabbed interface. Once I get my old code ported to the new SDK, tested for 4.3, I’ll start working on the 5.0 version to be released later on this year.
At least the weather outside is HORRIBLE, so I’m not missing out on any quality MC riding today. :/
If you managed to catch my previous post on the iPhone Cellular Location Tracking Controversy, you saw that I did a little more research into the issue than most of the other articles. Or, at least I showed my work. So why post today? I’m going to walk through a check to see if turning of ‘Location Services’ and *not* approving any of the services to use it for a week, stopped or at least reduced the amount of data recorded.
Here is what I did…. and at the end of the article, we’ll both know the results.
Syncing the iPhone to laptop
Connected my phone to the laptop at 08:49, and specifically told iTune to sync. Once that was done, I changed to the iPhone backup directory:
Looking for updated files
:Backup me$ cd /Users/me/Library/Application\ Support/MobileSync/Backup
Next, I checked to see which directories had been most recently updated:
:Backup me$ ls -ltr
total 0
drwxr-xr-x 1929 me staff 65586 Mar 16 2010 21562bef54882a56a05f4047db0dd1ea95783af1
drwxr-xr-x 1323 me staff 44982 Apr 2 08:16 d56742670a5e045f4a76ebb7fd93c728054c0ebe-20110402-081551
drwxr-xr-x 719 me staff 24446 Apr 25 16:33 669ed5e78e2afe06caad469294edd80d4b3261b9
drwxr-xr-x 1371 me staff 46614 Apr 26 08:49 d56742670a5e045f4a76ebb7fd93c728054c0ebe
Locating the Manifest files that contain filename for the consolidated.db data file. This netted 4 database files. The one I am most interested in is the one created during the sync at 08:49 this morning.
:Backup me$ find . -name 'Manifest.mbdb*' -exec ls -l {} \;
-rw-r--r-- 1 me staff 226086 Apr 2 08:16 ./d56742670a5e045f4a76ebb7fd93c728054c0ebe-20110402-081551/Manifest.mbdb
-rw-r--r-- 1 me staff 167152 Apr 2 12:21 ./669ed5e78e2afe06caad469294edd80d4b3261b9/Manifest.mbdb
-rw-r--r-- 1 me staff 167022 Apr 25 16:33 ./669ed5e78e2afe06caad469294edd80d4b3261b9/Snapshot/Manifest.mbdb
-rw-r--r-- 1 me staff 232090 Apr 26 08:49 ./d56742670a5e045f4a76ebb7fd93c728054c0ebe/Manifest.mbdb
Changing to the directory, I ran the python script that lists contents of the db, and it’s data files, looking for the true name of the consolidated.db. There are over 1300 data files in that directory. It looks like the data file name remains unchanged (4096c9ec676f2847dc283405900e284a7c815836).
Now that I know where the file is, I’m going to copy it to my home directory, and compare it to the other DB files I’ve saved off over the last week. Looking at the list, you can see that the size of the file has not changed, since I started to track this last week. Now, that does not necessarily mean there are no new records in the table, but, it’s a pretty decent indication that it does not. But, an examination of the table, and comparison to the data from the last extract will quickly tell the tail!
:d56742670a5e045f4a76ebb7fd93c728054c0ebe me$ cp 4096c9ec676f2847dc283405900e284a7c815836 ~/iPhoneTracking.3.db
:~ me$ ls -ltr iPhone*
-rw-r--r-- 1 me staff 19128320 Apr 21 10:19 iPhoneLocation.1.db
-rw-r--r-- 1 me staff 225280 Apr 21 10:21 iPhoneLocation.2.db
-rw-r--r-- 1 me staff 19128320 Apr 21 13:23 iPhoneLocation.4.db
-rw-r--r-- 1 me staff 19128320 Apr 21 15:13 iPhoneTracking.1.db
-rw-r--r-- 1 me staff 19128320 Apr 22 14:24 iPhoneTracking.2.db
-rw-r--r-- 1 me staff 19128320 Apr 26 09:16 iPhoneLocation.3.db
Comparing the data. 22-APRIL vs. 26-APRIL.
I simply turned off Location Services on my phone last week, after storing the snapshot on 22-APRIL. During that time I used several apps that use some sort of location information, and in the cases where I was prompted to provide location services, I declined.
But first things first. I think it’s important to show that there is more than just the controversial CellLocation data in this database file. Here is the full list of tables included in consolidated.db
The table that is supposed to contain the data, is CellLocation. Lets show what is in the last 5 records entered in that table. Here are the fields, then the last 5 records:
sqlite> .header ON
sqlite> select * from CellLocation limit 1;
MCC MNC LAC CI Timestamp Latitude Longitude HorizontalAccuracy Altitude VerticalAccuracy Speed Course Confidence
22-APRIL
sqlite> select Timestamp,Latitude,Longitude,HorizontalAccuracy,Speed,Confidence from CellLocation order by Timestamp desc limit 5;
Timestamp|Latitude|Longitude|HorizontalAccuracy|Speed|Confidence
325110108.640637|47.24654626|-122.43737727|2164.0|-1.0|70
325110108.640637|47.24717628|-122.43819308|500.0|-1.0|50
325110108.640637|47.24570667|-122.43808859|2138.0|-1.0|50
325110108.640637|47.2472279|-122.43625974|1550.0|-1.0|70
325110108.640637|47.24575543|-122.43641382|500.0|-1.0|50
26-APRIL
:~ me$ sqlite3 iPhoneTracking.3.db
SQLite version 3.6.12
sqlite> .header ON
sqlite> select Timestamp,Latitude,Longitude,HorizontalAccuracy,Speed,Confidence from CellLocation order by Timestamp desc limit 5;
Timestamp|Latitude|Longitude|HorizontalAccuracy|Speed|Confidence
325110108.640637|47.24654626|-122.43737727|2164.0|-1.0|70
325110108.640637|47.24717628|-122.43819308|500.0|-1.0|50
325110108.640637|47.24570667|-122.43808859|2138.0|-1.0|50
325110108.640637|47.2472279|-122.43625974|1550.0|-1.0|70
325110108.640637|47.24575543|-122.43641382|500.0|-1.0|50
CONCLUSION
Based on the evidence collected from my phone, it indicates that turning LOCATION SERVICES OFFDOES STOP CellLocation LOGGING!. So.. there you have it.. My research. I’ve shown my work. Explained my methodology. You can trust me or not, but if you have some evidence, beyond some huckster’s article, that indicates I’m wrong, PLEASE let me know! If I missed something, I want to correct my research and conclusion.
The Great iPhone Location File Controversy – is it really a problem?
Unless you have been living under a rock, or use a Windows Mobile Device (no difference), you no-doubt have heard about the reports floating around in the last day or so about the infamous consolidated.db location history file that is maintained on each 3G enabled iOS4 devices such as the iPhone and 3G iPad.
In fact, the number of articles discussing this issue (and now this one is also joining the fray) is extensive.
The article references this page [iPhoneTracker], where you can download and app, or the source code to compile a program to read your consolidated.db file. However, first you must find it! The instructions for finding the file were not completely accurate, there are some references with path misspellings etc. So, I’m going to re-do those pages, show you how I did it, include the Python script I ran to read the database file, and finally the steps I went about to move the file, compare snapshots of the file, and see if turning off location services, as it purported, solves this problem
First order of business is to get the App. Since I’m smart and use a MAC (and LINUX, but I don’t sync my phone to LINUX, so that’s not going to be discussed any further) I grabbed this zip file, extracted the app inside, and dropped it in my Applications pane.
Running the program, I see this:
As you can see, I don’t do much wandering around. Zoomed in you can see some of the places along the West Coast I have wandered since I purchased the current device. The App will display ALL data, or you can have it just display a specific weeks’ full of data, form any time frame in the device. Here is a shot of some travel I did during Thanksgiving 2010.
To say the dataset is full of inaccuracy’s is an understatement. Just look at this map of the last two days of travel. I can assure you, I was not in Sumner, nor in Olympia or any of those other places on the eastern side of the sound in a long time, much less that last two days:
And yet another, from the middle of last year. You can see a lot of ‘hits’ on Vancouver island. However, I have NEVER been there. Ever!
OK, so, I hope you can see that, the use of the data has it’s limitations. It’s not very accurate. In face it’s pretty inaccurate in enough cases to make it’s utility, dubious.
But, I wanted to know more, so I delved deeper into the files and went in search of the nefarious SQLite file itself. First stop was this page, where I grabbed a script, applied some mentioned patches, located the backups directory and find my consolidated location files (I found 4).
Here is the patched Python script:
#!/usr/bin/env python
import sys
def getint(data, offset, intsize):
"""Retrieve an integer (big-endian) and new offset from the current offset"""
value = 0
while intsize > 0:
value = (value<<8) + ord(data[offset])
offset = offset + 1
intsize = intsize - 1
return value, offset
def getstring(data, offset):
"""Retrieve a string and new offset from the current offset into the data"""
if data[offset] == chr(0xFF) and data[offset+1] == chr(0xFF):
return '', offset+2 # Blank string
length, offset = getint(data, offset, 2) # 2-byte length
value = data[offset:offset+length]
return value, (offset + length)
def process_mbdb_file(filename):
mbdb = {} # Map offset of info in this file => file info
data = open(filename).read()
if data[0:4] != "mbdb": raise Exception("This does not look like an MBDB file")
offset = 4
offset = offset + 2 # value x05 x00, not sure what this is
while offset < len(data):
fileinfo = {}
fileinfo['start_offset'] = offset
fileinfo['domain'], offset = getstring(data, offset)
fileinfo['filename'], offset = getstring(data, offset)
fileinfo['linktarget'], offset = getstring(data, offset)
fileinfo['datahash'], offset = getstring(data, offset)
fileinfo['unknown1'], offset = getstring(data, offset)
fileinfo['mode'], offset = getint(data, offset, 2)
fileinfo['unknown2'], offset = getint(data, offset, 4)
fileinfo['unknown3'], offset = getint(data, offset, 4)
fileinfo['userid'], offset = getint(data, offset, 4)
fileinfo['groupid'], offset = getint(data, offset, 4)
fileinfo['mtime'], offset = getint(data, offset, 4)
fileinfo['atime'], offset = getint(data, offset, 4)
fileinfo['ctime'], offset = getint(data, offset, 4)
fileinfo['filelen'], offset = getint(data, offset, 8)
fileinfo['flag'], offset = getint(data, offset, 1)
fileinfo['numprops'], offset = getint(data, offset, 1)
fileinfo['properties'] = {}
for ii in range(fileinfo['numprops']):
propname, offset = getstring(data, offset)
propval, offset = getstring(data, offset)
fileinfo['properties'][propname] = propval
mbdb[fileinfo['start_offset']] = fileinfo
return mbdb
def process_mbdx_file(filename):
mbdx = {} # Map offset of info in the MBDB file => fileID string
data = open(filename).read()
if data[0:4] != "mbdx": raise Exception("This does not look like an MBDX file")
offset = 4
offset = offset + 2 # value 0x02 0x00, not sure what this is
filecount, offset = getint(data, offset, 4) # 4-byte count of records
while offset < len(data):
# 26 byte record, made up of ...
fileID = data[offset:offset+20] # 20 bytes of fileID
fileID_string = ''.join(['%02x' % ord(b) for b in fileID])
offset = offset + 20
mbdb_offset, offset = getint(data, offset, 4) # 4-byte offset field
mbdb_offset = mbdb_offset + 6 # Add 6 to get past prolog
mode, offset = getint(data, offset, 2) # 2-byte mode field
mbdx[mbdb_offset] = fileID_string
return mbdx
def modestr(val):
def mode(val):
if (val & 0x4): r = 'r'
else: r = '-'
if (val & 0x2): w = 'w'
else: w = '-'
if (val & 0x1): x = 'x'
else: x = '-'
return r+w+x
return mode(val>>6) + mode((val>>3)) + mode(val)
def fileinfo_str(f, verbose=False):
if not verbose: return "(%s)%s::%s" % (f['fileID'], f['domain'], f['filename'])
if (f['mode'] & 0xE000) == 0xA000: type = 'l' # symlink
elif (f['mode'] & 0xE000) == 0x8000: type = '-' # file
elif (f['mode'] & 0xE000) == 0x4000: type = 'd' # dir
else:
print >> sys.stderr, "Unknown file type %04x for %s" % (f['mode'], fileinfo_str(f, False))
type = '?' # unknown
info = ("%s%s %08x %08x %7d %10d %10d %10d (%s)%s::%s" %
(type, modestr(f['mode']&0x0FFF) , f['userid'], f['groupid'], f['filelen'],
f['mtime'], f['atime'], f['ctime'], f['fileID'], f['domain'], f['filename']))
if type == 'l': info = info + ' -> ' + f['linktarget'] # symlink destination
for name, value in f['properties'].items(): # extra properties
info = info + ' ' + name + '=' + repr(value)
return info
verbose = True
if __name__ == '__main__':
mbdb = process_mbdb_file("Manifest.mbdb")
mbdx = process_mbdx_file("Manifest.mbdx")
sizes = {}
for offset, fileinfo in mbdb.items():
if offset in mbdx:
fileinfo['fileID'] = mbdx[offset]
else:
fileinfo['fileID'] = ""
print >> sys.stderr, "No fileID found for %s" % fileinfo_str(fileinfo)
print fileinfo_str(fileinfo, verbose)
if (fileinfo['mode'] & 0xE000) == 0x8000:
sizes[fileinfo['domain']]= sizes.get(fileinfo['domain'],0) + fileinfo['filelen']
for domain in sorted(sizes, key=sizes.get):
print "%-60s %11d (%dMB)" % (domain, sizes[domain], int(sizes[domain]/1024/1024))
I placed the script in my home directory for now. Later I’ll move it off to the Applications directory. Setting the script to executable, I then set out to locate the manifest db files. To do this, I leveraged the find utility (don’t worry Windoze users… you’re not missing this utility, you never had it in the first place). I thus located these 3 manifest db files. The one I’m most interested in is dated today:
Now it’s time to run the python script, and grep for the filename I need.
Filename in hand, I check and verify it’s existence. The important part of the data returned is this:
That number is the real filename. Checking that I see that the file is there. Making a copy of that file available in my home directory (using cp to copy it… that means ‘copy’ for you Windoze users reading from your bunkers).
Word on the street, is that this is a SQLite database file. I should be able to confirm that with a simple strings test, and the rumor is confirmed:
I opened the database file, and selected the first 5 records, and last 30 records from the CellLocation table (rumored to contain the data of interest).
Now, the time stamping get’s a little tricky.. it’s seconds since January 01, 2001 (I really don’t want to do the GMT / epoch offsets right now), but I don’t need to worry about that, all I really care about is that LAST location the phone recorded for me. If it did, in fact, honor my demand to turn OFF location services, my last point of origin should be in or north of Purdy.
Checking this Latitude and Longitute with Lougle Maps (OK, so it’s a corny movie reference, move on with your big bad selves)… I see….
Well, this does not bode well for the Apple ‘researchers’ that say turning off Location Services solves this problem. As far as I can tell it DOES NOT. I’ll be doing a little more research on this myself later, when I have time to verify the timestamps. But for now, it looks like, regardless if you like it or not.. Big Brother Steve Jobs is WATCHING!!!!
Apr 20, 2011 … iLounge news discussing the iOS 4 devices quietly track, store users’ locations. Find more iPad news from leading independent iPod, iPhone, …
www.ilounge.com/…/ios–4–devices-quietly-track-store-users-locations/ – Cached
Apple tracking location of iOS4 device users, researchers say …
Apr 20, 2011 … A team of researchers have discovered that iOS4 is secretly obtaining your location and recording it to a hidden file, raising obvious …
www.betanews.com/article/Apple-tracking…iOS4–device…/1303319892
Got an iPhone or 3G iPad? Apple is recording your moves – O’Reilly …
Apr 20, 2011 … Ever since iOS 4 arrived, your device has been storing a long list of ….. Why not just visit http://oo.apple.come from any IOS4 device and …
radar.oreilly.com/2011/04/apple-location-tracking.html
While checking my Apps stats, I noticed that most of my sales have been from Europe. Europe? Really? How / Why? Germany and Italy were in there too, not just English speaking countries. So I had to ponder, just how many places are listing my ‘New’ app in their App Store Aggregators? Well, I found these links to my iCIDR app in a number of locations, a couple of which surprised me:
No comments or ratings. Plus the HTML the scrapped off another site (AppShopper.com) has one of the screen shots overlaying the text. Nice. 😐
DeMartini Videos
OK, this one is out there. It’s one of those click aggregation, sites. And no, I did not include the link, if you want to send them click revenue, you can find it with Google, it’s on the LAST page or results. Currently my App is no longer mentioned, but the cached version on Google shows it was pulled / scraped off another page because of my last name. And no, I am not related (as far as I know) to that clown at Electronic Arts in San Mateo.
If you’d like to find out more, and possibly pick up a copy yourself, click on the App Store icon.
Organizing ones learned lessons does not take much effort. The key is consistency, documenting things in a common mode (such as a binder, or a small note book, etc.). For decades I have preferred to use small bound ‘journal’ type books. Once full, the retire to my book-case for future reference. They have been incredibly useful over the years, holding esoteric bits of data generally accessible by myself recalling the rough dates I wrote relevant code, or learned a new programming language, reference that with the dated pages in the books (I ALWAYS date the pages in my notebooks) and voila.. if I had a personal epiphany, I recorded it there.
This time, I’m trying something a little different. Taking those same notes, but this time making them public for others to hopefully gain from the things I’ve learned. So, on with the show.
Creating a multi-line NSString object
If you have battled with maintainability in long NSStrings, I found the simple solution. Oddly, a couple of hours searching on the web did not even get close to showing me this. I just used some old C language line continuation syntax, figured out how Objective-C like to do it, and voila…, problem solved.
It’s quite simple really. The trick is the slash right after the closing double-quote. If you have whitespace, iOS 4.x will nick you with a warning. It still compiled and ran, but a warning is there for a reason, and this syntax throws none.
As with all these sorts of posts, I hope it helps someone else.
NSString* appStoreLink = @"http://itunes.apple.com/us/app/icidr/id400066695?mt=8&ign-mpt=uo%3D4";
NSString* msg = [NSString stringWithFormat:\
@"Check out this cool App I found in the App Store!\n"\
"\n"\
"%@ helps you understand CIDR Block IP notation. It's packed with some great "\
"features I think you'll find very useful.\n"\
"\n"\
"Version %@ of %@ is available now, just follow this App Store for more information:\n"\
"%@"\
,appName
,version
,appName
,appStoreLink];
yes, that’s REAL code from one of my apps.
Dismissing a Keyboard after UITextField input
Strategy entails using the keyboards ‘Return’ key to signal that one is done. Seems useful, but only if you have a single line text input. In my case, that’s what I’m looking at, single line input, so that’s the solution I’m going to try.
First things first, rename the Return key to Done. Ah… so now you see how to prompt the user to hit the enter key when they are ‘Done’. Tricky. Dirty-tricky? Maybe, but it will work.
WAS:
This is accomplished by changing the ReturnKey property dropdown available in the UITextField property inspector. The dialog looks like this:
NOW:
OK, that was the EASY part… the next part requires cutting some code, over-riding some methods and thinking a few things through.
The tricky part is understanding that you need to make sure your object has implemented UITextFieldDelegate. This is how that might look:
Following that you’ll need to enable viewDidLoad (boilerplate code) and implement some delegation:
- (void)viewDidLoad {
UITextField *seeText = (UITextField *) [self.view viewWithTag:102]; // try to locate the object with the tag
seeText.delegate = self; // assign a delegation.
[super viewDidLoad];
}
But the fun is not quite over yet.. The textFieldShouldReturn method will need to be defined to execute the abandonment of the first responder:
// Should trap all Keyboard Return Events
- (BOOL) textFieldShouldReturn:(UITextField*)textField {
[textField resignFirstResponder];
return YES;
}
You also need to know something about wiring classes and the File Owner together in the relevant Nib file. But you know how that plays out already, right?
UPDATE: 19-NOV-2010
After banging my head into the table for, uh, about 3 hours trying to get the ‘viewDidLoad‘ method to fire off… while digging around in the dusty corners of sites.. I FINALLY found THE ANSWER to this dilema. So.. now I’m going to add it in here so I don’t effing for get as well!!!
Display only numbers for certain keyboard events
It turns out this was just as easy as changing the Return button on the main keyboard to read Done. The same dropdown is play. The option I selected was Numbers and Punctuation. It looks like this:
Dismissing the Keyboard after any Button Press
** This is the 3rd thing I need to tackle. First I have to get some math stuff ironed out and tested, as well as some more advanced string deconstruction and manipulation. This will be an important thing to get worked out, since the keyboard will cover 1/2 my UI but the main button is still visible, meaning people will hit that instead of closing the keyboard first. That needs to be taken into consideration and coded for. People don’t want to click twice when they can click once. Seems pretty logical to me.
Regular Expression Solutions
About 8 hours of hunting, hacking, a little screaming and finally some yelling in rejoice.. I have sorted out, FINALLY a simple, contained example of Regular Expression executing in Objective-C. This may for work you, it may not. It might not have the error control you like, well.. you’re getting it for free so.. don’t get too worked up about it.
Basically, you’re going to need to use the regex.h C libraries to get it done. The upside is that it’s already on your system. Here is the snipped of code that I used to do some regexing on a string. Obfuscated since I’m not going to show exactly what I’m doing (oops.. my tin hat almost fell off). I’ve added a few comments. Now.. how did I learn this? By a lot of trial and error, frustrated looks at ‘iPhone Cookbooks’ that are so out of date 1/3 of the code is depricated… and then.. I found this little gem: Advanced Strings In Cocoa
so most of the credit goes to those that went before I.
- (BOOL)validateString:(NSString*)seeStr {
// Take the textField apart into pieces for computation
NSString* pattern = @"^[:character:]$";
NSString* result = nil;
regex_t preg;
int err = regcomp(&preg,[pattern UTF8String],REG_EXTENDED);
if(err) {
char errbuf[256]; // This was the biggest mistake I was making, not using CHAR here
regerror(err,&preg,errbuf,sizeof(errbuf));
UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Internal Error" message:@"ERROR Code 17" delegate:nil cancelButtonTitle:@"OK"otherButtonTitles:nil] autorelease];
[av show];
[NSException raise:@"CSRegexException" format:@"Could not compile regex %@: %s",pattern,errbuf];
}
const char *cstr=[seeStr UTF8String]; // This is another important bit of casting
regmatch_t match;
if(err = regexec(&preg,cstr,1,&match,0)==0){
result = [[[NSString alloc] initWithBytes:cstr+match.rm_so length:match.rm_eo-match.rm_so encoding:NSUTF8StringEncoding] autorelease];
// UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"MATCH!!!" message:result delegate:nil cancelButtonTitle:@"OK"otherButtonTitles:nil] autorelease];
// [av show];
return YES;
}
else {
char errbuf[256];
regerror(err,&preg,errbuf,sizeof(errbuf));
// [NSException raise:@"CSRegexException" format:@"Could not complete a match %@: %s",pattern,errbuf];
return NO;
}
It worked like a charm, I used a very complex pattern (not shown here) for a long string validation and it was spot on. And quick. And it worked. I hope this helps someone.
String Splitting
It turns out that slitting strings is Pretty Easy, or at least a lot easier that I had expected. This is a part of my daily programming life.. string manipulation… and one of those most common manipulations are splitting things apart into arrays for iterative processing.
So.. how hard is it to do in Objective-C? Not had at all, in fact, it’s all that it takes!
NSString *msg = @"The Dog/Cat is lazy"; // included here for context of msg
NSArray *parts = [[NSArray alloc] initWithArray:[msg componentsSeparatedByString:@"/"]];
Yeap.. that’s all it takes!!
Now let’s say the string was this: “The Dog/Cat is lazy”. And I want to get the first ‘part’ of that sentence, the part before the ‘/’. It’s as easy as pie (based on the line of code above):
NSString *aboutDog = [parts objectAtIndex:0];
So the variable aboutDog would contain the string at the first index (indexes start at 0 but you know that, because you’re not a sap developing for Windoze) and the value there is… TADA… The Dog. Fun. Easy… and if you know the index count (working on that) you can build a simple loop to do whatever you want!
NSString to Integer
The pain of robust variable casting… means you can’t be PERL/PHP lazy with your variables… you’d better know what you are putting in there, or where you are using it. So.. sometimes you feel like a nut uh.. string, and some times you don’t. Today I didn’t so off with it’s head! Sorta..
In this little story.. the string is named parts and I’m going to make a copy of it in the form of an integer with the name bits. So.. there you have my parts and bits all laid out for you to see (and if you’re a cute girl under 40, and you like what you see, give me a ring… uh huh). Uh.. digressing.. yeah.. code. Sorry. So that’s all there is to it. You’re welcome.
int bits = [[parts objectAtIndex:1] intValue];
Objective-C Math – just the basics Mama
App Store and Device Icon General Recommendations
General .png image sizes for Apple iPhone / iPad / iPod Apps:
App Store
512×512 .png
App Icon
57×57 .png
Spotlight Icon
29×29 .png
Add a line to UI View with UI Builder
Seems like a simple enough thing to handle, but I don’t see any elements that would provide this function.
Sending Things off to e-Mail Helper App
I finally had time to dig into this and find out how to make it all work.
There are a few things you must do to get In-App e-mail working. The first of which is to Add the Mail Framework to your set of frameworks. See the screen snipped here. The one you want is UIMessageFramework:
Once that has been added to your Framework, the fastest road to deployment that I found was to add the function right into the view you’re working with. Sure, it’s better from the statndpoint of pure OO programming to class this out, but I have a simple tool (from the standpoint of the UI, it was not simple for me to write the mathy bits) and it does not warrant strict OO policy enforcement.
So.. I just added the following (bold) to my View’s header file:
With the required framework referenced and appropriate delegation added, it’s off the the main code (.m) file.
You will need this block of code for the mail controller. Good news is that the SDK IDE will basically write the entire method for you, just need to add braces and you’re off:
Finally, you write the bits for sending the mail. How you call this, is up to you. I used a ToolTab Navigation button to trigger it. Do as you please. As a bonus, I top my hand on multi-line (visually) singular NSString construction. Here is where the rubbers meet the roadies:
- (IBAction)shareApp:(id)sender {
MFMailComposeViewController *picker =
[[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
NSString* appStoreLink = @"http://itunes.apple.com/us/app/icidr/id400066695?mt=8&ign-mpt=uo%3D4";
NSString* msg = [NSString stringWithFormat:\
@"Check out this cool App I found in the App Store!\n"\
"\n"\
"Version %@ of %@ is available now, just follow this App Store for more information:\n"\
"%@"\
,@"1.0"
,@"iCIDR"
,appStoreLink];
[picker setSubject:[NSString stringWithFormat:@"Check out this cool App I found (%@)",appName]];
[picker setMessageBody:msg isHTML:NO];
[self presentModalViewController:picker animated:YES];
[picker release];
}
Random Character String Generation
Crude but effective. I know there has to be a better way to do this, but for today, for now, for the moment, it’s going to be this:
NSString *pool = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-(NSString *) genString: (int) len {
NSMutableString *rand = [NSMutableString stringWithCapacity: len];
for (int i=0; i
CIDR Convert(er) is a simple to use tool that allows rapid deconstruction and understanding of any valid CIDR block notation.
For example. You’ve received a block of IP’s from your ISP. Maybe they are add-ons to your existing network. Perhaps you are deploying a completely new network. When you look at the provisioning worksheet and see the notation 17.251.200.70/25 you will want to know what IPs are part of that range. Instead of trying to do perform the 32-bit math in your head, or on a calculator, why not just use this handy tool? If you with a simple push of a button you’d have known:
I look forward to creating more useful, and more entertaining apps before Christmas Time.
The iCIDR App (link) is currently being reviewed by the Apple Store team. I hope to have it cleared and posted for download soon. This is my first app to go through the process, so I don’t expect it will be smooth. I’m sure there are some things that even the pages and pages of specifications and preparation documents did not fully cover, or at least I didn’t get the intent.
When I have more information about the status of the App, I will be posting it here.
Other applications are moving forward in their development.
Some of these new applications include 2 games, and 3 more technical tools. More information to come when I can talk about it.
What is that weird little device that seems to serve no purpose? It’s not a laptop, not phone, not a book nor hot plate.
Well, I am about to find out, and those of you following my blog can too. In fact I’m typing this blog entry with one right now. It’s only spent 4 days in my care to date, but so far this weird ‘little’ thing has engendered itself to me, my kids and a couple of other people whom have had some time to really try one out, beyond a little demo at the local electronics retailer
Even if this becomes little more than an eBook reader, I feel good about the investment. I do think this will find a place in my daily technology and recreation routines.
For instance, I can say already that it’s a fantastic way to enjoy a streamed movie or TV show anywhere you have some network but no TV. My first test of this was to enjoy 3 episodes od Galactica, streamed by Netflix to the iPad. I loved it.
I’ll have much more to say about it as I try out some daily business tasks. One of the first will be setting up some sample photography galleries to show prospective clients.
Another will be use of the device in the day to day administration of systems and IT management.
Stick around as I explore the ups and downs of the iPad over the next month or so.
Along with the iPad I am testing out Apples new Apple TV. Both are getting rave reviews in my house right now.
I am pleased to announce that the first Application to roll off the assembly line, is in the final testing phase.
The first in a series of utility applications is soon to be released to the Apple iTunes Application Store, and made available for public consumption.
App 01 is primarily designed for Systems Administrators. Providing a pair of commonly used tools, that come in handy more every day, but are most useful when you find yourself off-site, troubleshooting a networking issues, or in need of providing access credentials to other members of your organization. Having this handy pair of tools, will make your day just that much easier.
More information about this exciting development will be made available on my new Applications Site, located here: Apps by David. Right now, this is the only screen shot available for public distribution.
When testing has completed there will be a lot more information about this nifty little app to go around.