How to switch the code/build for the device or simulator

“My Pacakge” uses AdMob for showing ad in the application. The bad thing about AdMob library is it is not compatible with iOS 4 simulator (so many linking error occurs). I found the way to avoid these errors in the apple document. Switching code with pre-processor macros and exclude AdMob library from simulator build are the answer.

Compiling Source Code Conditionally for iOS Applications
There may be times when you need to run code on the simulator but not on a device, and the other way around. On those occasions, you can use the preprocessor macros TARGET_OS_IPHONE and TARGET_IPHONE_SIMULATOR to conditionally compile code.

So I changed the code like below to remove AdMob lib dependency for the iPhone simulator build.

#if TARGET_IPHONE_SIMULATOR
  UIView *ad;
#else
  AdMobView *ad;
#endif

One more thing necessary for switching the code is library linking. Build setting needs conditional linking otherwise linking error occurs.

Opening Project info dialog then select Build tab. Find “Other Linker Flags” setting and select “Add Build Setting Condition” from Action menu (lower left corner menu).

Custom Linker Setting

You can pick up conditions of sdk (device or simulator and its versions) and specify library or framework link settings (or other build settings).

Link:

Editing Conditional Build Settings (developer.apple.com)

Now you can automatically switch setting based on device or simulator.

How to trigger MKAnnotationView’s callout view without touching the pin? – Stack Overflow

But there is a catch to get benvolioT's solution to work, the code

for (id currentAnnotation in mapView.annotations) {
  if ([currentAnnotation isEqual:annotationToSelect]) {
    [mapView selectAnnotation:currentAnnotation animated:FALSE];
  }
}

should be called from – (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView, and nowhere else.

The sequence in which the various methods like viewWillAppear, viewDidAppear of UIViewController and the – (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView is called is different between the first time the map is loaded with one particular location and the subsequent times the map is displayed with the same location. This is a bit tricky.

via How to trigger MKAnnotationView’s callout view without touching the pin? – Stack Overflow.

Functions for CGRect

In the cocoa (cocoa touch) framework, CGRect structure are used in many places because its rendering system depends on Core Graphics library. Here are the useful functions for CGRect structure.

Function Description
CGRectMake() Creates CGRect structure from integer values

// creates CGRect with  x=0, y=0, width=100, height=100
CGRect rect = CGRectMake(0, 0, 100, 100);
CGRectFromString() Creates CGRect structure from string

// creates CGRect with x=10, y=20, width=100, height=200
CGRect rect = CGRectFromString(@"{{10, 20}, {100, 200}}");
NSStringFromCGRect() Creates NSString object for specified CGRect structure. It is same format as the argument for CGRectFromString().

CGRect rect = CGRectMake(0, 0, 100, 100);

// outputs {{0, 0}, {100, 100}}
NSLog(@"%@", NSStringFromCGRect(rect));
CGRectEqualToRect() Checks whether given two CGRect are equal in both size and position.

CGRect rect1 = CGRectMake(0, 0, 100, 100);
CGRect rect2 = CGRectMake(10, 20, 100, 100);

// returns false
CGRectEqualToRect(rect1, rect2);
CGRectIntersection() Returns the intersection of two rectangles. Note that if two rectangles do not intersect, it returns the null rectangle.

CGRect rect1 = CGRectMake(0, 0, 100, 100);
CGRect rect2 = CGRectMake(10, 20, 100, 100);
CGRect intersect = CGRectIntersection(rect1, rect2);

// returns {{10, 20},{90, 80}}
NSLog(@"%@", NSStringFromCGRect(intersect));
CGRectIsNull() Checks null

CGRect rect1 = CGRectMake(0, 0, 100, 100);
CGRect rect2 = CGRectMake(200, 200, 100, 100);
CGRect intersect = CGRectIntersection(rect1, rect2);

// returns YES (1)
NSLog(@"%d", CGRectIsNull(intersect));

There are more functions for this purpose. Check Apple’s website for the detail.

How to change the carrier name in the iPhone simulator

iPhone simulator shows “Carrier” as default carrier name. You can change this name whatever text you want.

1. Open ~/Library/Application Support/iPhone Simulator/User/Library/Preferences/com.apple.springboard.plist file with Property List Editor application

2. Add a new Row with key name “SBFakeCarrier”.

3. Set its value as whatever you want.

Property List Editor

4. Save plist file and that’s it. You will see the text you entered in step 3 in the iphone simulator.

Open URL from application

Pretty simple. This call terminates the application and starts Mobile Safari browser with specified URL.

  [[UIApplication sharedApplication] openURL: [NSURL URLWithString: @"http://www.apple.com/"]];

How to define private methods … sort of

There is no private or protected methods concept in Objective-C. I think it is related to the architecture of invoking method in Objective-C. Each method is invoked like [self method] style or [self performSelector:@selector(method)]. Internally, Objective-C runtime resolves method implementation by searching method name. This architecture gives flexibility to call method and also allows to have “category” but it is hard to support private method.

Apple still can enhance around this area to bring access control but until that time I think unnamed category is the simplest and easiest way to implement private method like declaration.

ClassA.h file

@interface ClassA {
}
- (void) publicMethod;
@end

ClassA.m file

@interface ClassA()
- (void) privateMethod;
@end

@implementation ClassA
- (void) publicMethod {
}

#pragma mark -
#pragma mark Private methods
- (void) privateMethod {
}
@end

Interesting discussions are going on at Stackoverflow.com

How to remember the setting (user defaults) easily

NSUserDefautls object automatically loads and saves small information. Along with primitive value like BOOL, integer or float, NSUserDefaults can handle objects like NSArray, NSData, NSDictionary, NSString.

// Save a default
[[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"ShowWarning"];

// Read  BOOL warning value from NSUserDefaults
BOOL showWarning = [[NSUserDefaults standardUserDefaults] boolForKey:@"ShowWarning"];

setObject: method is for setting class object and boolForKey: method is specifically used for getting BOOL value.

Capture view contents into an UIImage object

By combining UIGraphicsBeginImageContext() and -renderInContext in CALayer, you can draw contents into a image (UIImage) object. It is like screen capture.

UIGraphicsBeginImageContext(view.frame.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGContextTranslateCTM() modifies the x- and y- coordinates (otherwise it starts from (0,0)). By using CGContextTranslateCTM(), you can change the start capturing point so that it can capture limited area in the UIScrollView content.

CGSize pageSize = CGSizeMake(320, 480);
int currentPage = 2;
UIGraphicsBeginImageContext(pageSize);
CGContextRef resizedContext = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(resizedContext, 320 * currentPage, 0);
[scrollView.layer renderInContext:resizedContext];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Ref:
Capture UIImage with offset into UIScrollView

Set border around the view

There is no border property in UIView…. classes but we can access CALayer class to set border. Since layer property is defined in the UIView class, all of UIView inherited class can use this property to set border. It needs to have #import <QuartzCore/QuartzCore.h> to access CALayer.

view.layer.borderWidth = 1;
view.layer.borderColor = [[UIColor grayColor] CGColor];

Calling selectors with multiple arguments – Stack Overflow

In Objective-C, a selector’s signature consists of:

  1. The name of the method (in this case it would be ‘myTest’) (required)
  2. A ‘;’ (colon) following the method name if the method has an input.
  3. A name and ‘:’ for every additional input.

Selectors have no knowledge of:

  1. The input types
  2. The method’s return type.

Here’s a class implementation where performMethodsViaSelectors method performs the other class methods by way of selectors:

@implementation ClassForSelectors

- (void) fooNoInputs {
  NSLog(@"Does nothing");
}

- (void) fooOneIput:(NSString*) first {
  NSLog(@"Logs %@", first);
}

- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
  NSLog(@"Logs %@ then %@", first, second);
}

- (void) performMethodsViaSelectors {
  [self performSelector:@selector(fooNoInputs)];
  [self performSelector:@selector(fooOneInput:) withObject:@"first"];
  [self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first" withObject:@"second"];
}

@end

The method you want to create a selector for has a single input, so you would create a selector for it like so:

SEL myTestSelector = @selector(myTest:);

via Objective-C: Calling selectors with multiple arguments – Stack Overflow.