Best objective-c questions in July 2011

Unit tests for memory management in Cocoa/Objective-C

21 votes

How would you write a unit test—using OCUnit, for instance—to ensure that objects are being released/retained properly in Cocoa/Objective-C?

A naïve way to do this would be to check the value of retainCount, but of course you should never use retainCount. Can you simply check whether an object's reference is assigned a value of nil to indicate that it has been released? Also, what guarantees do you have about the timing at which objects are actually deallocated?

I'm hoping for a concise solution of only a few lines of code, as I will probably use this extensively. There may actually be two answers: one that uses the autorelease pool, and another that does not.

To clarify, I'm not looking for a way to comprehensively test every object that I create. It's impossible to unit test any behavior comprehensively, let alone memory management. At the very least, though, it would be nice to check the behavior of released objects for regression testing (and ensure that the same memory-related bug doesn't happen twice).

About the Answers

I accepted BJ Homer's answer because I found it to be the easiest, most concise way of accomplishing what I had in mind, given the caveat that the weak pointers provided with Automatic Reference Counting aren't available in production versions of XCode (prior to 4.2?) as of July 23rd, 2011. I was also impressed to learn that

ARC can be enabled on a per-file basis; it does not require that your entire project use it. You could compile your unit tests with ARC and leave your main project on manual retain-release, and this test would still work.

That being said, for a far more detailed exploration of the potential issues involved with unit testing memory management in Objective-C, I highly recommend Peter Hosey's in-depth response.

If you can use the newly-introduced Automatic Reference Counting (not yet available in production versions of Xcode, but documented here), then you could use weak pointers to test whether anything was over-retained.

- (void)testMemory {
    __weak id testingPointer = nil;
    id someObject = // some object with a 'foo' property

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    {
        // Point the weak pointer to the thing we expect to be dealloc'd
        // when we're done.
        id theFoo = [someObject theFoo];
        testingPointer = theFoo;

        [someObject setTheFoo:somethingElse];

        // At this point, we still have a reference to 'theFoo',
        // so 'testingPointer' is still valid. We need to nil it out.
        STAssertNotNil(testingPointer, @"This will never happen, since we're still holding it.")

        theFoo = nil;
    }
    [pool drain];



    // Now the last strong reference to 'theFoo' should be gone, so 'testingPointer' will revert to nil
    STAssertNil(testingPointer, @"Something didn't release %@ when it should have", testingPointer);
}

Note that this works under ARC because of this change to the language semantics:

A retainable object pointer is either a null pointer or a pointer to a valid object.

Thus, the act of setting a pointer to nil is guaranteed to release the object it points to, and there's no way (under ARC) to release an object without removing a pointer to it.

One thing to note is that ARC can be enabled on a per-file basis; it does not require that your entire project use it. You could compile your unit tests with ARC and leave your main project on manual retain-release, and this test would still work.

The above does not detect over-releasing, but that's fairly easy to catch with NSZombieEnabled anyway.

If ARC is simply not an option, you may be able to do something similar with Mike Ash's MAZeroingWeakRef. I haven't used it much, but it seems to provide similar functionality to __weak pointers in a backwards-compatible way.

Parsing Objective-C code for static analysis

10 votes

I love static analysis and compile-time checks, almost to a fault, but most of my day job is in Objective-C. To resolve this tension, I'd like to be able to write my own analysis tools that I can run on my Objective-C projects.

But googling around the Internet suggests that people are having a hard time putting together a complete Objective-C grammar. One site basically recommends giving up.

I did find a grammar on the ANTLR website, but when I fired it up, I couldn't get it to parse anything at all. For example, it responded to the line:

void x();

with src/main/resources/somecode.m line 1:0 no viable alternative at input 'void'

:(

I took a closer look at the grammar and found the following disheartening disclaimer:

it's a work in progress, most of the .h file can be parsed

But I need something that can parse both interface and implementation.

Is there a complete Objective-C 2.0 grammar out there somewhere? I'd prefer something that can work with Scala (so anything Java compatible, like ANTLR, would be perfect), but at this point I'd be willing to adapt something designed for another parser toolkit.

As others mentioned, Clang would be the right solution. You can provide your own AST consumers, i.e. classes that will be invoked when going over the AST, leaving you not having to worry about parsing or messing with grammar.

Clang supports Objective-C in its entirety, and there's a lot of classes already in the static analyzer that you can model your own checks after. (in clang/lib/StaticAnalyzer/Checkers).

That directory contains a lot of static analyzer checkers, but you can also just create a normal AST consumer. Refer to http://code.google.com/p/chromium/wiki/WritingClangPlugins for more information.

Objective C - Replacing portion of string in NSString?

8 votes

I am using the following code to replace a portion of the string, this works for normal characters (alphabetical characters) but when it comes to symbols like "•" it can't replace the character.

Any solution?

[myString stringByReplacingOccurrencesOfString:@"•" withString:@"<BULLET_POINT>"];

You may not be able to literally insert non-ASCII characters like "•" in a source file. Try using the escape \u2022 instead.

myString = [myString stringByReplacingOccurrencesOfString:@"\u2022" withString:@"<BULLET_POINT>"];

Objective-C - Is !!BOOL Beneficial

8 votes

I'm looking over the diffs submitted to a project by another developer, and they have a lot of code that does !!<some BOOL value>. In fact, this seems to be their standard pattern for implementing boolean getters and setters. They've implemented their code like:

- (BOOL) hasId {
    return !!hasId_;
}
- (void) setHasId:(BOOL) value {
    hasId_ = !!value;
}

I've never seen this pattern before, and am wondering if there is any benefit in using it. Is the double-negation doing anything useful?

The double boolean operator just makes sure that the value returned is either a 1 or a 0. That's all : )

i want to convert NSData To double value in Iphone

8 votes

i want covert content of NSData Which is actually i need as a double type how can i convert it?

here 1ff46c56 7dd86f40 nsdata byte and i want in double

Assuming your data is exactly 8 bytes, you can convert it to a double using memcpy(3):

double ConvertNSDataToDouble(NSData *data)
{
    double d;
    assert([data length] == sizeof(d));
    memcpy(&d, [data bytes], sizeof(d));
    return d;
}

Note that this assumes that the data is in native endian format. If you know that the data is big- or little-endian, then you may need to endian-swap the bytes first.

C++ coming from Java and Objective-C

7 votes

So, I know both Java and Objective-C quite well, but (perhaps strangely) never really learned C++. Obviously, the languages are all related, but there are syntactical differences that I don't fully understand. Is there a nice document that describes the basics of C++, but still assumes the learner knows a programming language? Perhaps even a tutorial that aims to describe the differences between the languages. This is what I'm looking for.

Also, is there a good tutorial on how to use C++ code inside a Mac or iOS app? The reason I feel the need to learn C++ is I'm trying to port a C++ program, and I heard you can use C++ code and just wrap it in an Obj-C GUI. Could someone point me to some documentation/tutorials on how to do this?

Thanks!

Even though the languages of this family are all related, that does not mean that you can casually move from one to the other and expect to write beautiful code. You have to learn the language's idioms and idiosyncrasies, and experience its strengths and way of thinking.

I would recommend reading Stroustrup's original book (a modern edition, of course). It's the most definitive reference (short of the actual standard) and it is very clearly written. The benefit of this approach is that you will be taught to think "how would I do this in C++", rather than "how do I transliterate this piece of Java code to make it compile". (Also this approach does away with any risk you might have of thinking you should "learn C first". Don't.)

On MacOSX, either download and build the free GCC, or get XCode (which comes with GCC). For iOS I don't know, I have a suspicion that you cannot deploy native code on it.

what is the difference of the following const defintion

7 votes

Usually I use the first one to define const, but I dont know the difference of the following clearly.

static NSString* kFetcherCallbackThreadKey = @"_callbackThread";

static NSString* const kFetcherCallbackRunLoopModesKey = @"_runLoopModes";

NSString* const kFetcherRetryInvocationKey = @"_retryInvocation";

static const NSUInteger kMaxNumberOfNextLinksFollowed = 25;

In C, the static keyword, used outside a function, is used to declare a symbol that will be accessible only from the file in which it's declared. Kind of «private» global variables.

The const keyword means «constant». Read, the value can't be modified. Note the two statements are different:

const int * x;
int * const x;

The first one defines a pointer to a constant integer (its value can't be modified, but it can point to something else). The second one defines a constant pointer to an integer (the pointer value can't be modified, but the value of the int may be). So you can perfectly have:

const int * const x;

So in your case:

static NSString* kFetcherCallbackThreadKey = @"_callbackThread";

A pointer to a NSString instance that will be accessible only from the file in which it's declared.

static NSString* const kFetcherCallbackRunLoopModesKey = @"_runLoopModes";

A constant pointer to a NSString instance that will be accessible only from the file in which it's declared.

NSString* const kFetcherRetryInvocationKey = @"_retryInvocation";

A constant pointer to a NSString instance that may be accessed from other files of your project.

static const NSUInteger kMaxNumberOfNextLinksFollowed = 25;

A constant integer that will be accessible only from the file in which it's declared.

XCode/Instruments not showing memory leaks

7 votes

I'm following the Stanford iOS development lectures and I have a Calculator brain class which has been alloc init in a controller but I haven't released it in the dealloc.

- (CalculatorBrain *)brain
{
    if (!brain) 
        brain = [[CalculatorBrain alloc] init];

    return brain;

}

I ran from XCode -> Run with Performance Tool and the app started and no leaks appeared, I then clicked the home button in the iOS Simulator and nothing, I then double clicked the home button and closed the app and still nothing.

I also did Build & Analyse and it didnt spot anything

Could you let me know why its not picking it up?

It appears as if there is no detectable leak. Look at this line:

brain = [[CalculatorBrain alloc] init];

As long as brain points to an object, that object won't be considered a "memory leak". If at some point you do this,

brain = nil;

Then the leak will register. Deallocating the container object will also achieve this, but are you sure it's being deallocated? (It won't be deallocated when your program exits, for example.)

The problem: Leak detectors cannot detect all memory leaks -- this is a mathematically proven fact. Most detectors only detect unreachable objects, and many leak detectors are especially susceptible to false negatives -- in C it is hard to tell the difference at runtime between a pointer and an integer.

Edit: It sounds like your application only ever creates one instance of the controller, which only creates one instance of CalculatorBrain. If you think about what a memory leak really is, you can define it as unused memory that your program does not release back to the operating system.

  • While the program is running, CalculatorBrain is always in use and therefore it is not a leak.
  • When the program exits, the operating system automatically reclaims all memory used by your process, therefore there cannot be any memory leaks after a program exits.

If you want to create a leak to see what it looks like, you could create a new CalculatorBrain multiple times while your program is running, but forget to release the unused versions. In this scenario, as your program runs, more and more instances of CalculatorBrain would accumulate. On iOS and other embedded systems, this will generally crash your program. On a modern 64 bit computer it will gradually fill up the available swap space until you run out of swap, address space, or some other resource -- causing the program to crash or making the system very unresponsive.

Standard practice is to not care about deallocating objects which are supposed to exist for the entire program's run.

Instance variables declared in ObjC implementation file

7 votes

I was watching the WWDC ARC introduction video and I saw something I've never seen in ObjC before when some Apple engineer talked about a Stack example.

The following code was used for a stack example with ARC:

@implementation Stack { NSMutableArray *_array; }
- (id)init {
   if (self = [super init])
      _array = [NSMutableArray array];
   return self;
}
- (void)push:(id)x {
   [_array addObject:x];
}
- (id)pop {
   id x = [_array lastObject];
   [_array removeLastObject];
   return x;
}
@end

Please note the instance variable declared right after the @implementation directive.

Now the thing that surprised me, is that an instance variable could actually be declared in the implementation file, without it being a static variable. My questions would be the following:

  • Is this some new construct introduced in the SDK for iOS 5 or has this been possible for a long time?
  • Would it be good practice to declare instance variables in the implementation, if the instance variables are not to be accessed outside the object? It seems way cleaner then the use of the @private directive.

This is indeed a new language feature, and if you must declare your ivars (rather than simply declaring properties and letting the compiler generate ivars for you) it's a good practice. Your header files in theory should only expose public interface for your classes; everything else belongs in the implementation.

Sort NSArray of NSStrings like Addressbook on iphone sort

7 votes

I have an array of strings (names)

and i would like to sort them like how the address book on the iphone sorts them

  • eg: éli -> under E
  • eg: àli -> under A
  • eg: 4li -> under #

any suggestions?

You need to perform a diacritic insensitive comparison against the strings. NSString has a compare:options: method with an option of NSDiacriticInsensitiveSearch.

NSArray *array = [NSArray arrayWithObjects:@"éli", @"bob", @"earl", @"allen", @"àli", @"aaron", nil];

NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch];
}];

Edit:

Here is a full example that will section the results based on the first character diacritic insensitive. I put in a dictionary so you would need to keep track of the sorted keys on your own to display properly.

NSArray *array = [NSArray arrayWithObjects:@"éli", @"bob", @"earl", @"allen", @"àli", nil];

NSArray *sorted = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [(NSString*)obj1 compare:obj2 options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch];
}];

NSMutableDictionary *sectioned = [NSMutableDictionary dictionary];
NSString *firstChar = nil;

for(NSString *str in sorted)
{
    //Ignore empty strings
    if(![str length])continue;

    NSMutableArray *names = nil;

    //Compare the first character using diacritic insensitive search
    if([str compare:firstChar options:NSDiacriticInsensitiveSearch|NSCaseInsensitiveSearch range:NSMakeRange(0, 1)] == NSOrderedSame)
    {
        names = [sectioned objectForKey:firstChar];
    }
    else
    {
        //decomposedStringWithCanonicalMapping is where the magic happens
        //(it removes the accent mark)
        firstChar = [[str decomposedStringWithCanonicalMapping] substringToIndex:1];
        names = [NSMutableArray array];
        [sectioned setObject:names forKey:firstChar];
    }

    [names addObject:str];
}

NSLog(@"sorted: %@", sorted);
//This is sectioned like the address app
NSLog(@"sectioned: %@", sectioned);

How to synchronize tasks in different dispatch queues?

7 votes

I'm new to queues and I'm having some trouble setting up the following scheme.

I have three tasks that need doing.

Task A: Can only run on the main queue, can run asynchronously with task B, cannot run asynchronously with task C. Runs a lot but runs fairly quickly.

Task B: Can run on any queue, can run asynchronously with task A, cannot run asynchronously with task C. Runs rarely, but takes a long time to run. Needs Task C to run afterwards, but once again task C cannot run asynchronously with task A.

Task C: Can run on any queue. Cannot run asynchronously with either task A or task B. Runs rarely and runs quickly.

Right now I have it like this:

Task A is submitted to the main queue by a Serial Queue X (a task is submitted to Serial Queue X to submit task A to the main queue).

Task B is submitted to Serial Queue X.

Task C is submitted to the main queue by Serial Queue X, just like task A.

The problem here is that task C sometimes runs at the same time as task B. The main queue sometimes runs task C at the same time that the serial queue runs task B.

So, how can I ensure that task B and task C never run at the same time while still allowing A and B to run at the same time and preventing A and C from running at the same time? Further, is there any easy way to make sure they run the same number of times? (alternating back and forth)

You know, I think I had this problem on my GRE, only A, B, and C were Bob, Larry, and Sue and they all worked at the same office.

I believe that this can be solved with a combination of a serial queue and a dispatch semaphore. If you set up a single-wide serial dispatch queue and submit tasks B and C to that, you'll guarantee that they won't run at the same time. You can then use a dispatch semaphore with a count set to 1 that is shared between tasks A and C to guarantee that only one of them will run at a time. I describe how such a semaphore works in my answer here. You might need to alter that code to use DISPATCH_TIME_FOREVER so that task A is held up before submission rather than just tossed aside if C is running (likewise for submission of C).

This way, A and B will be running on different queues (the main queue and your serial queue) so they can execute in parallel, but B and C cannot run at the same time due to their shared queue, nor can A and C because of the semaphore.

As far as load balancing on A and C goes (what I assume you want to balance), that's probably going to be fairly application-specific, and might require some experimentation on your part to see how to interleave actions properly without wasting cycles. I'd also make sure that you really need them to alternate evenly, or if you can get by with one running slightly more than another.

c preprocessor macro ^ symbol?

7 votes

looking at this page: http://www.mikeash.com/pyblog/friday-qa-2010-12-31-c-macro-tips-and-tricks.html

I found this snippet of code with ^{ ... }() syntax, what are the caret/brackets doing?

#define MAX(x, y) (^{ \
    int my_localx = (x); \
    int my_localy = (y); \
    return my_localx > my_localy ? (my_localx) : (my_localy); \
}())

It looks like its creating an anonymous function or something. What is this concept called? Where can I read about it?

It's a C block. It's quite like an anonymous function (in use, not in structure). You can read more about them on Mike Ash's site and in Apple's documentation.

Enable and Disable NSLog in DEBUG mode

3 votes

I want to enable NSLog when I am in debug and disable it otherwise. A very simple thing is:

#ifdef DEBUG
NSLog(@"My log");
#endif

But all this #ifdef and #endif is borring... :( So I try other thing: (.pch is good place to put it)

#ifdef DEBUG
#   define NSLog(text) NSLog(text);
#else 
#   define NSLog(text) 
#endif

This work very fine (isn't recursive). But the problem is that NSLog have infinite arguments.

void NSLog(NSString *format, ...)

How I solve this to work in preprocessor mode?

This should do the trick:

 #ifdef DEBUG
 #   define NSLog(...) NSLog(__VA_ARGS__);
 #else 
 #   define NSLog(...)
 #endif

Difference between iPhone development and Mac OSX development

3 votes

This question is for all the programmers who code in iphone as well as the Mac OSX platform.

I have been searching on Google for quite some time, but I could not find any good answer, and so I am posting the question here. Please apologize if this is not a programming question.

  1. Question on development overview:

    I would like to know how the iphone development tools are different from Mac OSX development tools.

  2. Question on the programming language:

    Is the programming done in objective-c for mac-osx as well ? Will it be the same syntax and format (for example, to create a button or textField)... ?

  3. Question on the libraries:

    If the programming is done in Xcode, how will the classes and libraries for touch and navigation be for the development in Mac OSX. ? And is there an interface builder ?

  4. Question on Simulation and Testing:

    Is it as easy as iPhone development to simulate and test the app in a Simulator ?

  1. Many different UI elements and interactions.
  2. The same.
  3. Different.
  4. IMHO yes.

You may want to check out these posts to help you transition:

Jumping from iOS to OSX

Removing iOS SDKs from OSX

NSScrollView in a NSWindow

3 votes

I have an NSScrollView inside an NSWindow, but it seems to be disabled. It looks like it would work, but the scrollbars are unresponsive to the mouse or the scroll wheel.

When I put the exact same NSScrollView inside a window on a new XCode project, it works perfect. There is something about the way I am making the window that is preventing the scroll from working.

I've been able to simplify it to this example:

//Make a window
NSWindow* myWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(300, 300, 300, 300)
                                       styleMask:NSTitledWindowMask
                                       backing:NSBackingStoreRetained
                                       defer:NO];

//Make a scroll view
NSScrollView *scrollview = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300)];
[scrollview setHasVerticalScroller:YES];
[scrollview setAcceptsTouchEvents:YES];
[myWindow setContentView:scrollview];

//Add something big to the scroll view
NSButton* btn = [[[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 600, 900)] autorelease];
[scrollview setDocumentView:btn];

//Show the window
[NSApp arrangeInFront:self];
[myWindow makeKeyAndOrderFront:self];
[NSApp activateIgnoringOtherApps:YES];

Any ideas?

Your problem, based on some experimentation I just did, seems to be with specifying NSBackingStoreRetained. The docs say:

You should not use this mode. It combines the limitations of NSBackingStoreNonretained with the memory use of NSBackingStoreBuffered.

They also say:

In Mac OS X 10.5 and later, requests for retained windows will result in the window system creating a buffered window, as that better matches actual use.

This does not seem to be accurate; switching the buffer: argument to NSBackingStoreBuffered made the window and scroll view behave as expected for me. (The docs also say not to use NSBackingStoreNonRetained, and indeed, it seemed to have problems similar to NSBackingStoreRetained.)

Core Data: How to merge inserts/updates/deletes between two NSManagedObjectContext's while maintaining the merge as an undoable step?

2 votes

I have a document-based Core Data application (running on Mac OS X 10.5 and above) where I'm trying to use two NSManagedObjectContext's on the main thread. I'd like to merge the changes made in the secondary context into my main (primary) context. In addition, I want the changes that were merged in from the secondary context to be undoable and to cause the document to be marked "dirty". I guess my question is similar to "Undoing Core Data insertions that are performed off the main thread" but, ATM, I'm not using different threads.

I've been observing the NSManagedObjectContextDidSaveNotification (which gets sent from the second context when calling -[self.secondaryContext save:]) like this:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(mocDidSave:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:self.secondaryContext];

In the -mocDidSave: method called by the observer I tried to use -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] on the primary context to merge the changes from the secondary context into the primary context:

- (void)mocDidSave:(NSNotification *)notification
{
    [self.primaryContext mergeChangesFromContextDidSaveNotification:notification];
}

However, while the, say, inserted objects readily appear in my array controller, the document is not marked dirty and the isInserted property of the newly added managed objects is not set to YES. Also the insertion (into the primary context) is not undoable.

Re-faulting any inserted objects will at least mark the document dirty but the insertion is still not undoable:

- (void)mocDidSave:(NSNotification *)notification
{
    [self.primaryContext mergeChangesFromContextDidSaveNotification:notification];

    for (NSManagedObject *insertedObject in [[notification userInfo] objectForKey:NSInsertedObjectsKey]) {
        [self.primaryContext refreshObject:[self.primaryContext existingObjectWithID:[insertedObject objectID] error:NULL] mergeChanges:NO];
    }
}

W.r.t. -mocDidSave:, I had slightly better results with a custom implementation:

- (void)mocDidSave:(NSNotification *)notification
{
    NSDictionary *userInfo = [notification userInfo];

    NSSet *insertedObjects = [userInfo objectForKey:NSInsertedObjectsKey];
    if ([insertedObjects count]) {
        NSMutableArray *newObjects = [NSMutableArray array];
        NSManagedObject *newObject = nil;
        for (NSManagedObject *insertedObject in insertedObjects) {
            newObject = [self.primaryContext existingObjectWithID:[insertedObject objectID] error:NULL];
            if (newObject) {
                [self.primaryContext insertObject:newObject];
                [newObjects addObject:newObject];
            }
        }

        [self.primaryContext processPendingChanges];

        for (NSManagedObject *newObject in newObjects) {
            [self.primaryContext refreshObject:newObject mergeChanges:NO];
        }
    }

    NSSet *updatedObjects = [userInfo objectForKey:NSUpdatedObjectsKey];
    if ([updatedObjects count]) {
        NSManagedObject *staleObject = nil;
        for (NSManagedObject *updatedObject in updatedObjects) {
            staleObject = [self.primaryContext objectRegisteredForID:[updatedObject objectID]];
            if (staleObject) {
                [self.primaryContext refreshObject:staleObject mergeChanges:NO];
            }
        }
    }

    NSSet *deletedObjects = [userInfo objectForKey:NSDeletedObjectsKey];
    if ([deletedObjects count]) {
        NSManagedObject *staleObject = nil;
        for (NSManagedObject *deletedObject in deletedObjects) {
            staleObject = [self.primaryContext objectRegisteredForID:[deletedObject objectID]];
            if (staleObject) {
                [self.primaryContext deleteObject:staleObject];
            }
        }

        [self.primaryContext processPendingChanges];
    }
}

This causes my array controller to get updated, the document gets marked dirty, and the insertions & deletions are undoable. However, I'm still having problems with updates which aren't yet undoable. Should I instead manually loop over all updatedObjects and use -[NSManagedObject changedValues] to reapply the changes in the primary context?

This custom implementation would, of course, duplicate a lot of work from the secondary context on the main context. Is there any other/better way of getting a merge between two contexts while maintaining the merge as undoable step?

If you are not using separate threads, then you don't actually need to separate contexts. Using two context on the same thread adds complexity without gaining anything. If you don't know for certain you will employ threads, then I would highly recommend just using the one context. Premature optimization is the root of all evil.

Saves reset the Undo manager so you can't use NSManagedObjectContextDidSaveNotification to perform any operation that can be undone. As you found you can trick the app into thinking the document is dirty but you can't force the Undo manager to remember past the last save.

The only way to do that, to get unlimited undo, is to save multiple versions of the doc behind the scenes. IIRC, you can also serialize the undo manager so that it can be written to file and reloaded to backtrack.

Error: "Unrecognized selector" when using addObjects: on an NSMutableArray

2 votes

When executing

[self.blockViews addObject:curBlockView];

I get an error

2011-07-01 13:35:26.240 Block Breaker[42061:207] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x4e037a0

I am pretty new to Objective-C. Is it something in my init method?

//
//  GameEngine.h
//  Block Breaker
//
//  Created by Chris Muench on 7/1/11.
//  Copyright 2011 N/A. All rights reserved.
//

#import <Foundation/Foundation.h>


@interface GameEngine : NSObject {
    NSMutableArray *blockViews;
    int numBlockRows;
    int score;
}
@property (nonatomic, copy) NSMutableArray *blockViews;
@property int numBlockRows;
@property int score;

- (void) setup;
- (void) setupBlocks;
@end


//
//  GameEngine.m
//  Block Breaker
//
//  Created by Chris Muench on 7/1/11.
//  Copyright 2011 N/A. All rights reserved.
//

#import "GameEngine.h"
#import "Block.h"
#import "BlockView.h"


@implementation GameEngine
@synthesize blockViews;
@synthesize numBlockRows;
@synthesize score;

- (id) init
{
    if ((self = [super init])) 
    {
        self.blockViews = [[NSMutableArray alloc] init];
        self.numBlockRows = 2;
        self.score = 0;
    }
    return self;
}

- (void) setup
{
    [self setupBlocks];
}

- (void) setupBlocks
{
    float blockWidth = 10;
    float blockHeight = 10;
    float rowSpacing = 2;
    float colSpacing = 2;
    float currentX = 0;
    float currentY=10;
    float screenWidth = 200;

    for (int rowCounter=0;rowCounter<self.numBlockRows;rowCounter++)
    {

        while(currentX <=screenWidth)
        {
            Block *curBlock = [[Block alloc] initWithWidth:blockWidth height:blockHeight];
            BlockView *curBlockView = [[BlockView alloc] initWithFrame:CGRectMake(currentX, currentY, curBlock.width, curBlock.height)];
            curBlockView.block = curBlock;

            [self.blockViews addObject:curBlockView];           
            currentX+=blockWidth+colSpacing;
            [curBlock release];
            [curBlockView release];
        }

        currentX=0;
        currentY+=blockHeight+rowSpacing;
    }


}

@end

When you copy an NSMutableArray using the copy method, or a synthesized setter for which the property was specified as copy, you get an immutable copy, which means you essentially end up with a plain NSArray.* There is a method mutableCopy which will preserve the mutability, but I don't believe there's any way to specify that for a property.

If you want your array to be mutably copied when you set it, you'll have to write your own setter method, and specify that method in the property declaration.

@property (nonatomic, copy, setter=setBlockViewsByCopying) NSMutableArray * blockViews;

- (void) setBlockViewsByCopying: (NSMutableArray *)newBlockViews {
    NSMutableArray * tmp = [newBlockViews mutableCopy];
    [blockViews release];
    blockViews = tmp;
}

A side note, as @InsertWittyName mentioned in a comment, your code initializing blockViews will create a leak, because you have two claims of ownership on the array you're creating -- one for the alloc and one for the retain or copy that you get using the property:

self.blockViews = [[NSMutableArray alloc] init];
//  ^ One claim                    ^ Two claims
// Only one release later, when the property is set again!
// LEAK!

You should instead do:

self.blockViews = [NSMutableArray array];
// Creates an object you don't own which you then make one claim
// on using the setter

*Though as it is a class cluster, you really get some unspecified concrete subclass.

Unable to detect portrait orientation on iPhone

2 votes

I am displaying a modal view controller when I rotate landscape. I want to remove the modal view controller when I am in portrait. For some reason, my log statement doesn't appear when I go into portrait mode.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations.
    return (interfaceOrientation == UIInterfaceOrientationPortrait ||
                   interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ||
                   interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
                   interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}


-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
        toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {

        NSLog(@"showing chart");
        [self presentModalViewController:landscapeChartViewController animated:NO];
    }

    if (toInterfaceOrientation == UIInterfaceOrientationPortrait ||
        toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
        NSLog(@"dismissing chart");
        [self.parentViewController dismissModalViewControllerAnimated:NO];
    }
}

You can simplify this code a bit, might help narrow it down.

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return YES; // Return YES is the same as entering all interfaces.
}


-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {

    NSLog(@"showing chart");
    [self presentModalViewController:landscapeChartViewController animated:NO];
}

if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
    NSLog(@"dismissing chart");
    [self.parentViewController dismissModalViewControllerAnimated:NO];
    // self.parentViewController seems like a call FROM the modalViewController. 
    // This should be moved to the modalViewControllers implementation
}
}

Just from looking at it, I'm thinking you need to dismiss the modal view controller inside the modal view, not inside the parent view. So, you would use the landscape version inside your primary controller, and then add the "willAnimateRotation..." to the modal controller to handle the portrait rotation state.