How to become a better (iOS) developer.
I’m working with the iOS SDK since it’s release to the public ( March 6, 2008 ) and I have faced a lot of doubts during my learning curve, provisions, certificates, Obj-C, App Store, etc, and back then, the amount of developer resources (tutorial, articles, etc) besides the Apple Developer Portal was near to zero, so if my answer was not in the developer portal, I needed to solve it by myself, and that’s one of the reasons that make me want to create this blog, to help fellow developers that are starting the development for iOS. Yep, I am a little late for that, when I created iDevzilla the internet was already flooded with iOS Development blogs, but…
This will not be a technical post, but I want to share some point of views and tips that I think that will help to improve the iOS Developer Community and to help each one of you to become a better developer, and hey, if you have any tips, agree or disagree with any of my texts, please, let me know, write a comment, this is the one of the purpose of this blog, I want to improve myself as well
Frustration
I think that one of the most important qualities that any developer must have is: Know how to deal with frustration. Since I started to work as a developer, in every company that I worked on, there was always one feeling that I was able to see (in me and in others) with a great frequency. Frustration.
“It’s working for me, it should work for you”, “This crappy code is not working”, “This project that I downloaded from GitHub is not compiling at all”, “How the F#ck can I reproduce this issue?”, “OK, it’s impossible”, “It doesn’t make any sense”
These are probably the most common sentences that I was hearing (and saying as well), at least once in a week.
How to deal with this frustration? I think that’s very specific to every one, some like to listen to music, some like to just go out for some minutes, but what I can say for sure is, you will NOT solve ANY of your problems while frustrated, you will not think straight and you will probably blame everyone else for your own frustration. How many times you were stuck with a big problem all day, frustrated, with an unbelievable anger, and the next day you discover an easy way to fix in 10 minutes? Just stop, do whatever you need to do to relax, play UT2K4 and kill a lot of bastards with your flak cannon, go back to your problem and try to understand the issue, typing random codes or copying “ready to go” fixes from google will not help you.
RTFM – Read The Fuc#ing Manual
Yep, that’s a really big problem with us, developers. We think that we know everything and probably more then the ones who actually created the framework / language / the world. I think the most common answer that I give to someone is “Have you read the Apple’s documentation before you asked that?” and it’s not a surprise that the answer is always “no”, and it’s really no surprise AT ALL that A LOT of answers are in the documentation.
I’m a member of several mailing list about software development for iOS, and the amount of people who just want something ready to use, that don’t have a clue of how to do anything is amazing. Even here in iDevzilla, I’m flooded with comments of people like “Hey, do you have some example to solve my specific problem that’s so easy to solve just reading the post itself but I’m to lazy to try to understand the problem?” OK, that’s not how I receive the comments, but you got the picture.
I’m not complaining at all of people asking questions, I do all the time, but please, try to understand your own problem before asking to others, and try to solve before asking to others, anyone wants to do your homework but we DO want to help you with it.
That’s not a mailing list or blogs issue, it is very frequent in the work place. Yep, sometimes it is blazing fast to just ask before any search, faster and easier. No problem at all, but when this becomes a routine, it will drive your colleagues mad and they will probably think that you don’t know anything about anything, and maybe they will be right.
If you don’t know how to solve your problem, make sure that you understood what your problem really is, that you have read the documentation, that you have searched google for an answer and then ask your colleagues. You will learn a lot more solving the issues by yourself, trust me.
Creativity
There are some people who disagree with me, but I really think that you need a good creativity to be a good developer. You need to see the whole forest and not the trees, but hey, every leaf is important as well. It’s a cheesy saying, but it is true as well, and it’s not an easy task to see the leaf, tree and the forest, but that’s our job.
In order to be creative, everyone has different needs, again, I can’t help anyone with that, you need to figure it out by yourself what you need. What I discovered that helps me to concentrate and to really enjoy my work are :
- Quiet work environment;
- Play some games with the guys from time to time (We are now playing UT2k4, old but gold);
- Good equipment;
- Work with people smarter than you;
It’s awesome to work with a great team, with people who you know that are better developers than you. If you need to hire a developer for your company, please, don’t hire someone worst than you because you’re afraid to lose your job or something like that, you need to hire developers that are at least in the same level, otherwise, a snowball of failures will start
Conclusion
I think that the best advice that I can give to anyone starting apps development, or any other kind of development is: Stop, Think, Write. Don’t rush anything, and refactor is your friend. Sometimes you will need to think “Maybe it will be better to start from scratch”, and mean it. You can spend 2 days trying to solve this huge problem or 3 days building a new solution way better than the previous one since you already have the project knowledge.
To be a developer is a lot of fun when you learn how to deal with the hard times. Next time, instead of freaking out, just stop, get your mind out of the problem, get back to the problem with a new thinking mind, and then, write your solution
WWDC 2011 Countdown iPhone app
Yeah, I know, I’m really busy and didn’t have time to create another post, hope to have time to create another one soon, if you have any ideas for the next post, please, leave a comment with your request.
Horray, I’m going to WWDC 2011
YEY! Yes, I was lucky enough to buy the ticket before it ran out, horray! And since I can’t wait for it, I developed some simple WWDC 2011 countdown app, so I can count the seconds for it. I assume that the opening will be at 10:00AM PST, same as last time, but there’s no official opening time that I know about it.
Anyway, this is the app screenshot, and if you want to install in your device, fell free do download the source code here. Fell free to modify, change, and do whatever you want with this project.
See you there
Where am I? Know how to get your location using CLLocationManager
Yey, here I am again. I didn’t update my blog for a while, I was really busy with some projects, hmm, in fact I’m busy right now, but I want to write a new post \o/.
One thing that’s really useful and simple to do using the iOS SDK is getting the user location to do whatever your want (well, not whatever you want, stalkers, but you got it). So, we will need something to help us out to get the user location, giving a quick look at the documentation you can find the CLLocationManager Class.
The CLLocationManager class defines the interface for configuring the delivery of location- and heading-related events to your application.
And let’s see, how do we use this class? Take a look at the example bellow:
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.delegate = self;
[locationManager startUpdatingLocation];
Yep, that’s it, 4 lines of code and the locationManager now is looking for your location, pretty cool huh? You may ask “What is this desiredAccuracy property?”, well you should look at the documentation, it’s there for answer all our questions about the universe, but I’ll be a nice guy and copy it here
“You should assign a value to this property that is appropriate for your usage scenario. In other words, if you need the current location only within a few kilometers, you should not specify kCLLocationAccuracyBest for the accuracy. Determining a location with greater accuracy requires more time and more power.”
This property determines the precision of your CLLocationManager, it’s a const with 6 possible values, you should look at every one and use the one that best fits your needs.
OK, now our locationManager is updating your location, but how do we retrieve it? If you read the code carefully you may have seen that there’s a delegate assigned to self, right? This is how we will get our location. There’s 2 important delegate methods:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation ;
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;
The second one is used in case of some error, for some reason your device failed to retrieve your location, and the first one will give you the CLLocation, that has the latitude and longitude plus other cool things. This delegate will be called every time that the locationManager gets a new (and better) location
That’s all you need to get the location of the user, but latitude and longitude are boring, OK, not really lat and lng rocks \w/, but let’s do something more useful with them…
One More Thing…
We have the location, latitude and longitude, with a few lines of code, but let’s transform this in a real address so it’s human readable. Again, reading the documentation we will find the MKReverseGeocoder
“The MKReverseGeocoder class provides services for converting a map coordinate (specified as a latitude/longitude pair) into information about that coordinate, such as the country, city, or street. A reverse geocoder object is a single-shot object that works with a network-based map service to look up placemark information for its specified coordinate value.
And how it works? It’s pretty similar to the CLLocationManager class, just 3 lines of code and the reverse geocoded starts the job
reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:currentLocation.coordinate];
reverseGeocoder.delegate = self;
[reverseGeocoder start];
And just like the CLLocationManager, we need to implement the delegate to get the address, and they are:
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark ;
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error;
The first delegate will return the MKPlacemark, that has the address, so you can access the thoroughfare with the property thoroughfare like placemark.thoroughfare.
I did a sample project that search for the user location and when it finds the location the MKReverseGeocoder start to search for the user address. In my example I have a condition that the reverse geocoded will only begin if the locationManager finds a location with accuracy range of 200 meters.
if (currentLocation.horizontalAccuracy <= MINIMUM_DISTANCE) {
[self startReverseGeocodingWithCurrentLocation];
}
Download the Source Code Here.
Have fun
UIScrollView and Zoom
- (void)loadView {UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];scroll.backgroundColor = [UIColor blackColor];scroll.delegate = self;image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image.JPG"]];scroll.contentSize = image.frame.size;[scroll addSubview:image];scroll.minimumZoomScale = scroll.frame.size.width / image.frame.size.width;scroll.maximumZoomScale = 2.0;[scroll setZoomScale:scroll.minimumZoomScale];self.view = scroll;[scroll release];}
- Creating a UIScrollView with the same size as the main screen
- Setting the background color to black
- Assigning the delegate to self
- Creating an UIImageView with a image that’s already added on the project, don’t forget to declare the UIImageView on your .h file.
- Setting the contentsize to the full size of the image
- Adding the image to the UIScrollView
- Setting the minimum zoom scale to fit the iPhone screen horizontally, so the image with the lowest zoom level, will fit the screen
- Setting the maximum zoom to be 2 times the image size
- Setting the UIScrollView to start with the minimum zoom scale
- Assigning the UIScrollView to the UIViewController’s UIView
- Releasing the UIScrollView
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {return image;}
One More Thing
If you run your project, you may realize that the image is not on the center of your screen, even if you zoom, and here’s how you can center your view on UIScrollView while zooming. But no worries, I will help you out, just copy this method:
- (CGRect)centeredFrameForScrollView:(UIScrollView *)scroll andUIView:(UIView *)rView {CGSize boundsSize = scroll.bounds.size;CGRect frameToCenter = rView.frame;// center horizontallyif (frameToCenter.size.width < boundsSize.width) {frameToCenter.origin.x = (boundsSize.width – frameToCenter.size.width) / 2;}else {frameToCenter.origin.x = 0;}// center verticallyif (frameToCenter.size.height < boundsSize.height) {frameToCenter.origin.y = (boundsSize.height – frameToCenter.size.height) / 2;}else {frameToCenter.origin.y = 0;}return frameToCenter;}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {image.frame = [self centeredFrameForScrollView:scrollView andUIView:image];;}
UIScrollView – A really simple tutorial
It’s very common to have a large amount of data that we want to display on the iPhone/iPod, but there’s no way that we can fit all at the same time on the screen (even on the iPad), that’s one of the functionalities of the UIScrollView.
The UIScrollView it’s a very versatile class, you can handle zooming, panning, scrolling, etc, and I have no intention of explaining all the properties and delegates (well, if you want to know something about the UIScrollView, fell free to request it in the comments, just let me know =D ), the documentation itself is pretty good, so you should give it a look.
In this post I’ll create a very simple project with three scrollable UIViews just to get familiar with the UIScrollView, and in the next post I intend to do some simple zooming example. So, the next post will be about the UIScrollView as well.
The basics:
IMO, there’s 2 very important properties in UIScrollView, the contentSize and the contentOffset.
The contentsize is the width and height of your content, it’s a CGSize and a property of UIScrollView, let’s say that you have an image that’s 500×500, it would not fit on the iPhone screen, right? So, set your contentsize to 500,500. If you want to add more scrollable space at the bottom or at the top, you can use the property contentInset.top and contentInset.bottom, so you can add some extra space without changing the contentsize. And why would you need these insets? Well, if you have a UINavigationBar or a UIToolBar, like the photos app, you will use this.
Every UIScrollView has a scroll indicator (it’s visible by default, but if you want, you can hide it with showsHorizontalScrollIndicator and showsVerticalScrollIndicator), to give an indication of how far in the content you are, and you can change where the indicator starts using the scrollIndicatorInsets.top just like the contentInsets.
The contentOffset is the point that is currently visible, this point represents the top left of your screen. The contentOffset discards the contentInsets, so it can happen that the contentInset is negative, that’s not a problem.
The only thing that you need to have a functional UIScrollView is the UIView that you want to display and the contentSize of this UIView, so let’s start coding…
Create a View-based Application and name it SimpleScroll. Again, I always use the Window-based Application for my projects, but let’s pick the View-based just to speed things up.
Go to your SimpleScrollViewController class, in the loadView method and create your UIScrollView, we will create it with the same width and heigh as the view from SimpleScrollViewController
UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
scroll.pagingEnabled = YES;
If the value of this property is YES, the scroll view stops on multiples of the view bounds when the user scrolls. The default value is NO.
NSInteger numberOfViews = 3;for (int i = 0; i < numberOfViews; i++) {CGFloat xOrigin = i * self.view.frame.size.width;UIView *awesomeView = [[UIView alloc] initWithFrame:CGRectMake(xOrigin, 0, self.view.frame.size.width, self.view.frame.size.height)];awesomeView.backgroundColor = [UIColor colorWithRed:0.5/i green:0.5 blue:0.5 alpha:1];[scroll addSubview:awesomeView];[awesomeView release];}
The most important part in this for is to understand the xOrigin. This will place every UIView exactly where the previous UIView has stopped, in other words, each UIView will start at the end of the previous one.
scroll.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews, self.view.frame.size.height);
The contentSize is just the sum of the widths of the three UIViews, if the width of each UIView is 320, and we have three UIViews, your contentSize width will be 920.
[self.view addSubview:scroll];[scroll release];
- (void)loadView {[super loadView];self.view.backgroundColor = [UIColor redColor];UIScrollView *scroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];scroll.pagingEnabled = YES;NSInteger numberOfViews = 3;for (int i = 0; i < numberOfViews; i++) {CGFloat xOrigin = i * self.view.frame.size.width;UIView *awesomeView = [[UIView alloc] initWithFrame:CGRectMake(xOrigin, 0, self.view.frame.size.width, self.view.frame.size.height)];awesomeView.backgroundColor = [UIColor colorWithRed:0.5/i green:0.5 blue:0.5 alpha:1];[scroll addSubview:awesomeView];[awesomeView release];}scroll.contentSize = CGSizeMake(self.view.frame.size.width * numberOfViews, self.view.frame.size.height);[self.view addSubview:scroll];[scroll release];}
That is the tutorial, pretty simple, huh? Now you can show all the data that you want on this small screen Automating UI Testing
Why test your app?
- Avoid regressions
- Increase your app quality, therefore your users satisfaction
- Do something else while the script does the boring work
- Test manually only those more interesting scenarios.
UI Automation
Script language
cd ~/Library/Application\ Support/iPhone\ Simulator/ln -s 4.0.1 4.0
How to automate?
- Name: Accessibility labels gets translated into the name of your element
- Value : Value of a control, text from a textfield, and so on.
- Elements : Every element can contain zero or more elements, like a tableview cells
- Parent: Like elements, but one level back up
Verification
UIALogger.logPass(“yet, it’s OK”);UIALogger.logFail(“bummer”);
Logging
UIALogger.logMessage(“Log this”);
UIATarget.localTarget().captureScreenWithName(“myScreenshot”);
Tutorial
- (void)loadView {[super loadView];UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];[button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchDown];[button setTitle:@"Click me" forState:UIControlStateNormal];button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);[self.view addSubview:button];textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, self.view.frame.size.width – 20, 30)];textField.borderStyle = UITextBorderStyleRoundedRect;textField.textAlignment = UITextAlignmentCenter;[self.view addSubview:textField];}- (void)click {textField.text = @”MyTestApp”;}- (void)viewDidUnload {[textField release];textField = nil;}- (void)dealloc {[textField release];[super dealloc];}
app = UIATarget.localTarget().frontMostApp();mainWindow = app.mainWindow();button = mainWindow.buttons()[0];button.tap();var result = mainWindow.textFields()[0].value();UIALogger.logMessage(“Will tap on button”);if (result == “MyTestApp”) {UIALogger.logPass(“yey, it’s OK”);} else {UIALogger.logFail(“bummer”);}UIATarget.localTarget().captureScreenWithName(“myScreenshot”);UIALogger.logMessage(“Button tapped”);
Conclusion
NSLog: Logging Tips
int myInt = 1;float myFloat = 2.3;NSString *myString = @”Hello Log”;UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 40)];NSLog(@”Int [%i]“, myInt);NSLog(@”Float [%f]“, myFloat);NSLog(@”String [%@]“, myString);NSLog(@”Object [%@]“, myView);
Int [1]Float [2.300000]String [Hello Log]Object [<UIView: 0x5c07950; frame = (0 0; 20 40); layer = <CALayer: 0x5c07920>>]
NSString *test = @”Test “;NSLog(@”log: %@”, test);Result : log: TestNSString *test = @”Test “;NSLog(@”log: [%@]“, test);Result : log: [Test ]
NSStringFromCGSizeNSStringFromCGPointNSStringFromCGRect
#define MYLOG(fmt, …) NSLog((@”File [%s] Method [%s] Line [%d]: ” fmt),__FILE__, __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
MYLOG(@”Hello Log”);
- __FILE__ : file path and name.
- __PRETTY_FUNCTION__ : name of the method.
- __LINE__ : the line of the method
File [/Users/user/Desktop/Log/Classes/LogAppDelegate.m] Method [-[LogAppDelegate application:didFinishLaunchingWithOptions:]] Line [25]: Hello Log




