Monday 27 August 2012

XCode Notes Moving to XCode from Java


Looking at Objective C with a Java background is a bit of a challenge.

I am following Paul Hegarty IOS course which is ITunesU and I think is just follow-able by someone with Java knowledge. In fact Apple appear to be migrating aspects of Java into Objective C.

One thing I have noticed is that C++ Obj C people seem to make it a matter of pride to make "one liners". Code presented as an example is really long when a clear description (& clearer code IMO) is created by using several lines with well named intermediate variables. I admit there is a limit and the best way of writing a bug free line is to write no line at all, but I wonder how many long lines of code out there  reflect coding by rumourn or "chinese whispers" as opposed to understanding.

Reports here will probably reflect the tutorials and home work from there.

The best site for questions and answers appears to be Stackoverflow.

Answers tend to be larded with complex references however today I found out some useful stuff and record it here for future reference.

When to use pointers in referring to variables?

answer 1: From experience (!)
answer 2: In general use pointers for objects and not for primitives.

Strings

The @ symbol turns up a great deal when using strings. If you just use "" to denote strings, you will get a ! from the compiler because it will thin k you are trying to do things with characters.

Example. From the CHS sign button on my HP11 emulator.
NSString *leadingCharacter = [self.display.text:0] ;
if leadingCharacter != @"-";{<do something>}

One thing I had to do was make a CHS button which changes the sign of the number in the display (Which is a string). The following code checks if the first character is a '-' and puts one if if not and removes it if there is.
(Prior to calling I check that there is a string of length at least 1 already there.

if([self.display.text characterAtIndex:0] != '-')
   {
    self.display.text =  [NSString stringWithFormat:@"-%@", self.display.text])
     }
else
   {
    self.display.text = [self.display.text  substringFromIndex:1]
   }

How to find a substring in a string

Surprisingly difficult, in words you have to make a NSRange (not an object) by using the rangeOfString method on your string and then use the location instance variable location to compare to NSNotFound to see whether the ting was found.

I found a good answer here.

Here is my code

NSString *whatIAmLookingFor = @"sometext";
NSString *whereIAmLooking = @"some text maybe what I am looking for";
NSRange myRange = ( [whereIAmLooking rangeOfString:whatIAmLookingFor]);
if (myRange.location) !=NSNotFound} {do this} else {do that};
When asking question on stackoverflow the answers may often put three lines of code (for a beginner) into one. 

Testing Strings for Equality.When we want to test within an if statement for branching you might think that 
if (myString == @"*"){} would be a reasonable bit of code but because Objective C is an Object Oriented programming language, testing for equality is not quite as straightforward. 
With primitives such as double, int, char etc. this construct is fine but with a NSString, you  are dealing with an object and so first of all the line of code has to test for inequality between objects. This is compounded by the fact that in C you are dealing with NSString pointers and so the test above would only ever succeed if the two strings were one and the same object and so the pointers were the same.
What you need to do is test using the IsEqual method which is part of the NSString API.
This code is using the correct method.


if ([topOfStack isEqualToString:@"*"]){
    element = [NSString stringWithFormat:@"%@%@%@",rhs,topOfStack,lhs];    
    }

An object has to be completely equal to pass this equality test but this is what I want here.

XCode4 Wrinkles

Sometimes XCode throws a hissy fit and bungs loads of !s in the LH bar about faults on build. It is worth clicking the build  button and they may all just disappear.

How to manage memory.

XCode4 (which I am using) appears to have put in a (kind of ) garbage collector as in Java in the form of Automatic Reference Counting (ARC) which means that objects get removed when they have run out of use beacuse no other object is referencing them.
Hurray for that. I know memory management is a job that C++ programmers have to do and Java programmers do not.

Simple debugging.
At this stage I want to use print statement to debug. In Oh-C! this is

NSLog (@"Just done the thing in the line above, about to do the thing in the line below");

To print in some sensible way, the @ formatters are important for getting the outputs in a sensible form.  They are listed here.

To print the contents of an object there is something like the toString() method in Java and this takes the form (for printing out)

NSLog(@" array contents %@",[<object> description]);


The Debugger.One of the optional Paul Hegarty Lectures introduces the debugger. For the lazy, here is a brief intro to the most useful thing he shows in that lecture. But really, go and see the whole thing.
This is really useful. The debugger is introduced nicely 
here. The first thing you will want to do is stop crashes juts taking you back to 'main'. Use the LHS debugger screen to set a trap for all exceptions, that means that a crash will take you  back to the point where the crash occurred. Big improvement on main.  In the left hand pane you click on the second icon from the right. Alt text is "Show the breakpoint Navigator", click on the plus at the bottom and choose the defaults in "Add Exception Breakpoint" and this will give you the breakpoint Navigator view in the RH picture below.

This is the LH pane in the XCode viewThe All Exceptions Trap is in the Navigator














Accessing Values and Properties and some illumination on all these [] and () and dot notation.

In general, call a method by 
[<object> <method>] 
and if the method has a parameter to send use  
 [<object> <method>:<parameter>]
You can access a property using dot notation.
<value of correct type> = <object>.<property>;

If you do  
<object>.<method>; 
i.e. you do not assign to a value because the method is void, the method will run but you will get a compiler warning that you should not use getters for side effects. In other words, if object.method is void then you are calling the method an an object so do [<object> <method>].

Finding out about method calls

The course I am following builds on a RPN calculator built using Model:View:Controller
.I have to make a clear button and initially I used the code
self.display.text=@"0";
self.display.history=@"";
self.brain.clear;
In the model  the only instance variable is a NSMutableArray with the various things entered by the calculator user in it.
I put a method called "clear" into the model that clears the array using the removeAllObjects method.
I got a warning from Xcode that "property access unused getters should not be used for side effects"

After some effort and this help I realised that I needed to use

[self.brain clear]

The message was effectively saying the following,
'[self.brain clear]' is calling the method in the class brain with the name 'clear' which should be used when calling a method.

self.brain.clear would be used if I was accessing a property in the object brain with the name clear and so would be on the RHS of an assignment of the correct type.

e.g. NSString *clearProperty = self.brian.clear

(assuming the method clear returned a String)

The reason it worked was that OBj-C treated the method clear as a 'getter' and ran the method which had the required effect, however as it was not on the RHS of an assignment I had used the 'getter' for a side effect.

I think this means that a void method would always be called using the notation [object.method <method name>];

No comments:

Post a Comment