Robert C. Martin: Clean Architecture and Design

Reset external display settings on mac

Using external display is a great thing. I prefer to use my big external screen rotated by 90º: quite useful for long docs.

The problem comes along when you remove the cable while the mac is sleeping: sometimes the system remembers that the screen is rotated but this no more synced with the monitor. It causes that almost half of the screen is not used. Moreover you cannot reset it from the system preferences.

In this case it’s better to drop all the remembered settings for the displays.

You can do it by deleting the “com.apple.windowserver[long text here]” files in “~/Library/Preferences”.

After you deleted the files just restart without saving the window states.

Analyzing binary libraries on Mac

If you want to know the architectures a library supports, just call:

lipo -info <libname>

lipo is also used to create fat-binaries.

If you want to look more deeply into a binary library the easiest way to use nm.

NM will list the whole structure of the library together with the public classes/method.

It’s under the Xcode.app bundle.

For example:

/Applications/Xcode.app/Contents/Developer/usr/bin/nm -g -U -A -m -arch armv7

The tools can be found at /Applications/XCode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin

The case of missing IPA creation option in Xcode

IPA is technically a small install package of iOS platform.
You can create it in XCode by creating an archive (Product/Archive menu point) and if the build is ready pressing the Distribution button on the right side of the appearing Organizer window. In the new appearing window just select Save for Enterprise or Ad-Hoc Deployment, sign with the proper Code Signing Identity and save to a folder.
You can send it to anybody who can install the app (of course the device should be in the profile).

Usually this just works, but sometimes it doesn’t because the Save for Enterprise... options is simply missing. This can happen if you use referenced libraries in your project.

To enable that option you have to take care of some settings.
First, set all related projects  Skip Install build option to Yes.
Second, you have to turn all Public headers to Project header.

The reason is that the build will create an app and also puts the other projects and public headers beside the project. So there will be an app with a lot of other files which is doesn’t seem a proper iOS app so XCode won’t let you create an install form it.

I don’t understand however why the build copies the public headers of a sub-project to the build folder of the app if the files doesn’t appear in the Copy headers section in the Build phases, but this just happen.

 

ObjC ivar/global var declaration – a clarification

You can declares iVar-s in header files but it’s better in the implementation, so they will be really invisible for others.
You should do this way:

@implementation MyClass {
    int firstiVar;
}
@synthesize anyProperty;

But what if you forget the parenthesis and you put the variable simply beside the @synthesize?
Like this:

@implementation MyClass

int firstiVar;

@synthesize anyProperty;

The compiler will treat it like other variables outside the class. So they will be global variables. Unfortunately in this case these variables is not just shared among all instances but shared in the whole project. What does it mean? It means if you set the value in one instance to 1, and later you set it to 2 in another instance, the value will be 2 for both (since you only have one instance in fact instead of two). AND since it wasn’t marked as static if you have an other global variable with the same name that will be shared together with the variables in the class, even if you did it accidentally.

WARNING: you won’t get any warning or error. It could be a pain in your ass to find these kind of bugs.

So just to clarify:

int firstVar; // global variable, shared and accessible in the whole project and all instances
static int firstStaticVar; // global variable shared among all instances, accessible from only this file

@implementation MyClass {
    int firstiVar;
static firstStaticIVar;// compile error, cannot do this
}

int secondiVar; // !!! the same as firstVar !!!
static secondStaticIVar; // the same as firstStaticVar

@synthesize anyProperty;

Good luck!

 

Using the background of a UITableView as a scroll indicator

There is a fancy solution to present the scrolling position of a tableview to the user using moving image as a background. The user can better imagine the size of the table view because the background image suggest where he/she is in the tableview.

How-To – short version

  1. Add a tableview
  2. create a scrollview with an imageview which size and contentSize is the same as the tableview
  3. add the scrollview as a background view of the tableview
  4. set the tableview to transparent
  5. Good To Know: the TableView is a ScrollView so you can handle all ScrollViewDelegate related methods. Just simply implement the ScrollView delegate methods where you implemented the TableViewDelegate methods: catch the tableview’s scrolling event and position the scroll position of the background scrollview accordingly

How-To – detailed version

The sample source uses ARC.

First, in the ViewDidLoad of your ViewController load the appropriate image, create an image view which presents it  and add the ImageView as the subview of your ScrollView:

- (UIView *)createBackgroundScrollViewWithFrame:(CGRect)tableViewFrame {

    // set up the image view, select a long image
    UIImage *img = [UIImage imageNamed:kImageName];

    // create image view with the image, the size should be long enough for the scroll
    UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
    imgView.contentMode = UIViewContentModeScaleToFill;
    imgView.frame = CGRectMake(0,0, tableViewFrame.size.width, img.size.height);

    // set up the background scroll view and add the image view
    UIScrollView *backgroundScrollView = [[UIScrollView alloc] initWithFrame:tableViewFrame];
    backgroundScrollView.userInteractionEnabled = NO;
    backgroundScrollView.contentSize = imgView.frame.size;
    [backgroundScrollView addSubview:imgView];

    return backgroundScrollView;
}

 

Second, set the ScrollView as the backgroundView of your tableView:

    // set the scroll view as the background view of the tableview
    myTableView.backgroundView = [self createBackgroundScrollViewWithFrame:theTableView.bounds];

Third, don’t forget to set the background color of the cells to clearColor if you use the tableView in grouped mode:

cell.backgroundColor = [UIColor clearColor];

Fourth implement the appropriate ScrollViewDelegate method of the TableView (scrollViewDidScroll). Notice that I modified the parameter to UITableView instead of UIScrollView. This is not necessary but makes to code more clear and you don’t have to cast a lot. We should calculate the correct position by the proportion of the contentSize of the TableView and the ScrollView.

// cheat a bit: modify the parameter to UITableView from UIScrollView
- (void)scrollViewDidScroll:(UITableView *)aTableview {

    if (aTableview != myTableView) {
        return;
    }
    UIScrollView *backgroundScrollView = (UIScrollView*)aTableview.backgroundView;

    // calculate the position of the scroll regarding to the position of the tableview
    float diffTableView = aTableview.contentSize.height - aTableview.frame.size.height;
    if (diffTableView>0) {
        float diffScroll = backgroundScrollView.contentSize.height - backgroundScrollView.frame.size.height;
        float newOffset = aTableview.contentOffset.y * (diffScroll/diffTableView);

        backgroundScrollView.contentOffset = CGPointMake(backgroundScrollView.contentOffset.x, newOffset);
    }
}

 

Notes: The image should be long enough to see the correct effect.

If you put a frame around your content you should play with margins and spacings:  you have to set up a header and footer and indent of each cell.

If you use sections take care of indenting the sections as well. You can achieve by implementing the  tableView:viewForHeaderInSection and return a UIView which contains a UILabel indenting appropriately.

You can set a semitransparent background color for each cell and/or you can use a faded image.

Download the sample project:

TableViewAutoScrollingBackground.zip

Enabling AirDrop – if it doesn’t work

Have you ever experienced that the AirDrop doesn’t work while it definitely should work? Two computers cannot see each other?

Ok, first check some cases – on both machines:

  1. You have a Mac OS X Lion OS installed
  2. wifi is turned on
  3. both machines has to have an opened Finder window and the AirDrop should be selected. If you move the selection form AirDrop on any of the machines it breaks the connection.
    How to select AirDrop: 

    1. It should be on the SideBar – open SideBar (View Menu). If it’s not there add it
    2. Select it by mouse/trackpad or keyboard: Cmd+Shift+R (works from almost everywhere in Lion)

If you checked everything and still cannot active (or select) the AirDrop than perhaps you have to enable it:

  1. open the terminal
  2. type the following and press enter:
    defaults write com.apple.NetworkBrowser BrowseAllInterfaces 1
  3. restart AirDrop: Alt+Cmd+Esc – in the popup select Finder, press Relaunch

I hope this will help for you.

iOS mock framework for unit tests

Mock objects are objects which behave like another business objects, but they don’t do more than you need to test a unit. For example they response with a static data.

Mock frameworks gives you the ability to define dynamically mock objects in the test method rather than define them in separate classes. The mock object will behave like an object you need to test the unit you want.

For iOS there is a great mocking framework: OCMock (http://ocmock.org)

ObjC advanced static code analyzer

There is a built in code analyzer in Xcode but unfortunately it’s not that we really need. It doesn’t check complexity, method sizes etc.

This was one of the missing features till now because fortunately there is a good one out already: OCLint (http://oclint.org/)

Unfortunately there is still no correct Xcode project file read support in it, but there is a dirty solution by recursively read all the .m files in a folder. On the developer’s site there is a basic script for it. Since it was a bit old I updated the script and now works well with the latest Xcode.

Just put the following script into a .sh file and run in the root folder of the project (check the paths before run)

#! /bin/bash

LANGUAGE=objective-c
ARCH=armv7
SYSROOT=/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk
CLANG_INCLUDE=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/3.1/include
PCH_PATH=target-Prefix.pch
FRAMEWORKS='/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/System/Library/Frameworks/'

INCLUDES='-I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk/usr/include'
for folder in `find . -type d`
do
  INCLUDES="$INCLUDES -I $folder"
done

FILES=''
for file in `find . -name "*.m"`
do
  FILES="$FILES $file"
done

oclint -x $LANGUAGE -arch $ARCH -isysroot=$SYSROOT -F $FRAMEWORKS -I $CLANG_INCLUDE $INCLUDES $FILES