Best objective-c questions in May 2011

CoreAnimation's threads

13 votes

Recently, I've been trying to find a way to analyze animations via GDB (for no other good reason than curiosity.) As I understand it, CoreAnimation runs it's animations in a separate thread(s). However, after suspending all active threads via GDB, my animation (specifically, the CAKeyFrameAnimation that UIImageView uses) were still running.

This leads me to believe that one of 2 things are happening:

1.) We're not privy to its thread(s) for whatever reason.

2.) I've missed something terribly obvious.

Any feedback on this issue is very much appreciated. Thanks.

Your actual animations are handed off to the SpringBoard process. This is why they don't stop when you pause all threads in your process using the debugger. You can see further evidence of this by using the VM Watcher instrument to see shared VM regions being allocated when you create animations. In this regard, SpringBoard functions sort of like the window server on OS X.

Pass a block to a C++ method from objective C

12 votes

I have a C++ helper class that I use with objective-C. I would like to pass the c++ class a block from a view controller (a callback) so that when it is executed I am on the main thread and can update the UI. I currently have a similar system working with function pointers and performSelector when the function is called. I would like an example of how to set up the c++ variable and how to pass an objective-C block to it and call it from the c++ class.

If this is not possible, can you think of another/better solution?

So is it just that you're not entirely familiar with the block syntax? If so, here's a quick example that should hopefully make sense if you're already familiar with function pointers (the syntax is more or less the same, but with the use of an ^ for declaring one [creating a closure is, of course, different]).

You probably want to set up a typedef for the block types just to save yourself repeating the same thing over and over, but I included examples for both using a typedef and just putting the block type itself in the parameters.

#import <Cocoa/Cocoa.h>

// do a typedef for the block
typedef void (^ABlock)(int x, int y);

class Receiver
{
public:
    // block in parameters using typedef
    void doSomething(ABlock block) {
        block(5, 10);
    }

    // block in parameters not using typedef
    void doSomethingToo(void (^block)(int x, int y)) {
        block(5, 10);
    }
};


int main (int argc, char const *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Receiver rcv;
    // pass a block
    rcv.doSomething(^(int x, int y) { NSLog(@"%d %d", x, y); });
    rcv.doSomethingToo(^(int x, int y) { NSLog(@"%d %d", x, y); });

    [pool drain];
    return 0;
}

When does an associated object get released?

12 votes

I'm attaching object B via associative reference to object A. Object B observes some properties of object A through KVO.

The problem is that object B seems to be deallocated after object A, meaning its too late to remove itself as a KVO observer of object A. I know this because I'm getting NSKVODeallocateBreak exceptions, followed by EXEC_BAD_ACCESS crashes in object B's dealloc.

Does anyone know why object B is deallocated after object A with OBJC_ASSOCIATION_RETAIN? Do associated objects get released after deallocation? Do they get autoreleased? Does anyone know of a way to alter this behavior?

I'm trying to add some things to a class through categories, so I can't override any existing methods (including dealloc), and I don't particularly want to mess with swizzling. I need some way to de-associate and release object B before object A gets deallocated.

EDIT - Here is the code I'm trying to get working. If the associated objects were released prior to UIImageView being completely deallocated, this would all work. The only solution I'm seeing is to swizzle in my own dealloc method, and swizzle back the original in order to call up to it. That gets really messy though.

The point of the ZSPropertyWatcher class is that KVO requires a standard callback method, and I don't want to replace UIImageView's, in case it uses one itself.

UIImageView+Loading.h

@interface UIImageView (ZSShowLoading)
@property (nonatomic)   BOOL    showLoadingSpinner;
@end

UIImageView+Loading.m

@implementation UIImageView (ZSShowLoading)

#define UIIMAGEVIEW_SPINNER_TAG 862353453
static char imageWatcherKey;
static char frameWatcherKey;

- (void)zsShowSpinner:(BOOL)show {
    if (show) {
        UIActivityIndicatorView *spinnerView = (UIActivityIndicatorView *)[self viewWithTag:UIIMAGEVIEW_SPINNER_TAG];
        if (!spinnerView) {
            spinnerView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
            spinnerView.tag = UIIMAGEVIEW_SPINNER_TAG;
            [self addSubview:spinnerView];
            [spinnerView startAnimating];
        }

        [spinnerView setEvenCenter:self.boundsCenter];
    } else {
        [[self viewWithTag:UIIMAGEVIEW_SPINNER_TAG] removeFromSuperview];
    }
}

- (void)zsFrameChanged {
    [self zsShowSpinner:!self.image];
}

- (void)zsImageChanged {
    [self zsShowSpinner:!self.image];
}

- (BOOL)showLoadingSpinner {
    ZSPropertyWatcher *imageWatcher = (ZSPropertyWatcher *)objc_getAssociatedObject(self, &imageWatcherKey);
    return imageWatcher != nil;
}

- (void)setShowLoadingSpinner:(BOOL)aBool {
    ZSPropertyWatcher *imageWatcher = nil;
    ZSPropertyWatcher *frameWatcher = nil;

    if (aBool) {
        imageWatcher = [[[ZSPropertyWatcher alloc] initWithObject:self keyPath:@"image" delegate:self callback:@selector(zsImageChanged)] autorelease];
        frameWatcher = [[[ZSPropertyWatcher alloc] initWithObject:self keyPath:@"frame" delegate:self callback:@selector(zsFrameChanged)] autorelease];

        [self zsShowSpinner:!self.image];
    } else {
        // Remove the spinner
        [self zsShowSpinner:NO];
    }

    objc_setAssociatedObject(
        self,
        &imageWatcherKey,
        imageWatcher,
        OBJC_ASSOCIATION_RETAIN
    );

    objc_setAssociatedObject(
        self,
        &frameWatcherKey,
        frameWatcher,
        OBJC_ASSOCIATION_RETAIN
    );
}

@end

ZSPropertyWatcher.h

@interface ZSPropertyWatcher : NSObject {
    id          delegate;
    SEL         delegateCallback;

    NSObject    *observedObject;
    NSString    *keyPath;
}

@property (nonatomic, assign)   id      delegate;
@property (nonatomic, assign)   SEL     delegateCallback;

- (id)initWithObject:(NSObject *)anObject keyPath:(NSString *)aKeyPath delegate:(id)aDelegate callback:(SEL)aSelector;

@end

ZSPropertyWatcher.m

@interface ZSPropertyWatcher ()

@property (nonatomic, assign)   NSObject    *observedObject;
@property (nonatomic, copy)     NSString    *keyPath;

@end

@implementation ZSPropertyWatcher

@synthesize delegate, delegateCallback;
@synthesize observedObject, keyPath;

- (id)initWithObject:(NSObject *)anObject keyPath:(NSString *)aKeyPath delegate:(id)aDelegate callback:(SEL)aSelector {
    if (!anObject || !aKeyPath) {
        // pre-conditions
        self = nil;
        return self;
    }

    self = [super init];
    if (self) {
        observedObject = anObject;
        keyPath = aKeyPath;
        delegate = aDelegate;
        delegateCallback = aSelector;

        [observedObject addObserver:self forKeyPath:keyPath options:0 context:nil];
    }
    return self;
}

- (void)dealloc {
    [observedObject removeObserver:self forKeyPath:keyPath];

    [keyPath release];

    [super dealloc];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    [self.delegate performSelector:self.delegateCallback];
}

@end

Even larger than your -dealloc issue is this:

UIKit is not KVO-compliant

No effort has been made to make UIKit classes key-value observable. If any of them are, it is entirely coincidental and is subject to break at Apple's whim. And yes, I work for Apple on the UIKit framework.

This means that you're going to have to find another way to do this, probably by changing your view layouting slightly.

Example or explanation of Core Data Migration with multiple passes?

11 votes

My iPhone app needs to migrate its core data store, and some of the databases are quite large. Apple's documentation suggests using "multiple passes" to migrate data to reduce memory use. However, the documentation is very limited and doesn't explain very well how to actually do this. Can someone either point me towards a good example, or explain in detail the process of how to actually pull this off?

I've figured out what Apple hints in their documentation. It's actually very easy but a long way to go before it's obvious. I'll illustrate the explanation with an example. The initial situation is this:

Data Model Version 1

enter image description here enter image description here

It's the model you get when you create a project with the "navigation based app with core data storage" template. I compiled it and did some hard hitting with some help of a for loop to create around 2k entries all with some different values. There we go 2.000 events with an NSDate value.

Now we add a second version of the data model, which looks like this:

enter image description here

Data Model Version 2

The difference is: The Event entity is gone, and we've got two new ones. One which stores a timestamp as a double and the second one which should store a date as NSString.

The goal is to transfer all Version 1 Events to the two new entities and convert the values along the migration. This results in twice the values each as a different type in a separate entitiy.

To migrate, we choose migration by hand and this we do with mapping models. This is also the first part of the answer to your question. We will do the migration in two steps, because it's taking long to migrate 2k entries and we like to keep the memory footprint low.

You could even go ahead and split these mapping models further to migrate only ranges of the entities. Say we got one million records, this may crash the whole process. It's possible to narrow the fetched entities down with a Filter predicate.

Back to our two mapping models.

We create the first mapping model like this:

1. New File -> Resource -> Mapping Model enter image description here

2. Choose a name, I chose StepOne

3. Set source and destination data model

enter image description here

Mapping Model Step One

enter image description here

enter image description here

enter image description here

The multi pass migration doesn't need custom entity migration policies, however we will do it to get a bit more detail for this example. So we add a custom policy to the entity. This is always a subclass of NSEntityMigrationPolicy.

enter image description here

This policy class implements some methods to make our migration happen. However it's simple in this case so we will have to implement only one method: createDestinationInstancesForSourceInstance:entityMapping:manager:error:.

The implementation will look like this:

StepOneEntityMigrationPolicy.m

#import "StepOneEntityMigrationPolicy.h"


@implementation StepOneEntityMigrationPolicy

- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance 
                                      entityMapping:(NSEntityMapping *)mapping 
                                            manager:(NSMigrationManager *)manager 
                                              error:(NSError **)error
{
    // Create a new object for the model context
    NSManagedObject *newObject = 
        [NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName] 
                                      inManagedObjectContext:[manager destinationContext]];

    // do our transfer of nsdate to nsstring
    NSDate *date = [sInstance valueForKey:@"timeStamp"];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];    

    // set the value for our new object
    [newObject setValue:[dateFormatter stringFromDate:date] forKey:@"printedDate"];
    [dateFormatter release];

    // do the coupling of old and new
    [manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];

    return YES;
}

Final step: the migration itself

I'll skip the part for setting up the second mapping model which is almost identical, just a timeIntervalSince1970 used to convert the NSDate to a double.

Finally we need to trigger the migration. I'll skip the boilerplate code for now. If you need it, I'll post here. It can be found at Customizing the Migration Process it's just a merge of the first two code examples. The third and last part will be modified as follows: Instead of using the class method of the NSMappingModel class mappingModelFromBundles:forSourceModel:destinationModel: we will use the initWithContentsOfURL: because the class method will return only one, maybe the first, found mapping model in the bundle.

Now we've got the two mapping models which can be used in every pass of the lopp and send the migrate method to the migration manager. That's it.

NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];
NSDictionary *sourceStoreOptions = nil;

NSURL *destinationStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataMigrationNew.sqlite"];

NSString *destinationStoreType = NSSQLiteStoreType;

NSDictionary *destinationStoreOptions = nil;

for (NSString *mappingModelName in mappingModelNames) {
    NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];

    NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];

    BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL
                                               type:sourceStoreType
                                            options:sourceStoreOptions
                                   withMappingModel:mappingModel
                                   toDestinationURL:destinationStoreURL
                                    destinationType:destinationStoreType
                                 destinationOptions:destinationStoreOptions
                                              error:&error2];
    [mappingModel release];
} 

Notes

  • A mapping model ends in cdm in the bundle.

  • The destination store has to be provided and should not be the source store. You can after successful migration delete the old and rename the new one.

  • I did some changes to the data model after the creation of the mapping models, this resulted in some compatibility errors, which I could only solve with recreating the mapping models.

Static Library using frameworks in specific projects

11 votes

I have created a static library containing all my generic classes. Some of these classes use frameworks.

Now I have two projects, one that uses some classes that use frameworks, and one that doesn't use any of the classes that use frameworks.

Because Static Libraries don't support including frameworks (if I am correct). I have to include the frameworks in the project that uses them. But when I compile the project that doesn't use any of the framework-classes the compiler breaks because it still requires the frameworks. Now I know it tries to compile all the (unused) classes from the library because I use the Linker Flag '-ObjC' to prevent 'unrecognized selector' errors.

Does anyone know how to compile only the required source files per project? And prevent from all frameworks having to be included in all projects that use my static library?

First of all, you are right in that a static library cannot include any framework nor other static libraries, it is just the collection of all object files (*.obj) that make up that specific static library.

Does anyone know how to compile only the required source files per project?

The linker will by default only link in object files from the static library that contain symbols referenced by the application. So, if you have two files a.m and b.m in your static library and you only use symbols from a.m in your main program, then b.o (the object file generated from b.c) will not appear in your final executable. As a sub-case, if b.m uses a function/class c which is only declared (not implemented), then you will not get any linker errors. As soon as you include some symbols from b.m in your program, b.o will also be linked and you will get linker errors due to the missing implementation of c.

If you want this kind of selection to happen at symbol rather than at object level granularity, enable dead code stripping in Xcode. This corresponds to the gcc option -Wl,-dead_strip (= linker option -dead_strip in the Build settings Info pane for your project). This would ensure further optimization.

In your case, though, as you correctly say, it is the use of the "-ObjC" linker flag that defeats this mechanism. So this actually depends on you. If you remove the -Objc flag, you get the behavior you like for free, while losing the stricter check on selectors.

And prevent from all frameworks having to be included in all projects that use my static library?

Xcode/GCC support an linking option which is called "weak linking", which allows to lazily load a framework or static library, i.e., only when one of its symbols is actually used. "weak linking" can be enabled either through a linker flag (see Apple doc above), or through Xcode UI (Target -> Info -> General -> Linked Libraries).

Anyhow, the framework or library must be available in all cases at compile/link time: the "weak" option only affects the moment when the framework is first loaded at runtime. Thus, I don't think this is useful for you, since you would need anyway to include the framework in all of your projects, which is what you do not want.

As a side note, weak_linking is an option that mostly make sense when using features only available on newer SDK version (say, 4.3.2) while also supporting deployment on older SDK versions (say, 3.1.3). In this case, you rely on the fact that the newer SDK frameworks will be actually available on the newer deployment devices, and you conditionally compile in the features requiring it, so that on older devices they will not be required (and will not produce thus the attempt at loading the newer version of the framework and the crash).


To make things worse, GCC does not support a feature known as "auto-linking" with Microsoft compilers, which allow to specify which library to link by means of a #pragma comment in your source file. This could offer a workaround, but is not there.


So, I am really sorry to have to say that you should use a different approach that could equally satisfy your needs:

  1. remove the -ObjC flag;

  2. split your static library in two or more parts according to their dependencies from external frameworks;

  3. resort to including the source files directly.

Write Objective-C class from scratch

11 votes

Hi,

I'd like to write an Objective-C class without Cocoa or GNU's Object.h (for educational purposes). I dug around the net and it seems to me that quite a lot of stuff that one would expect to "come with the language", such as classes and message sending are actually defined in files written by third parties, such as objc-runtime.h.

Is there any documentation about what is really pure Objective-C and what is part of the runtime / frameworks? And what functionality do I have to implement to get a working environment without using any third-party code such as Object.h or objc-runtime.h (note again that this is for educational purposes, not for production code)?

Thanks for any insight!

Really, the only thing you must take care of yourself if you don't inherit from NSObject is object creation and destruction; methods otherwise behave the same way regardless of their parent class. Features like KVC and memory management are features of OpenStep/Cocoa, but not required as part of the language.

Here's a class from scratch:

@interface MyClass { // note the lack of a superclass here
    @private Class isa;
}
+ (MyClass *)create;
- (void)destroy;

- (int)randomNumber;
@end


@implementation MyClass
+ (MyClass *)create {
    return class_createInstance(self, 0);
}

- (void)destroy {
    object_dispose(self);
}

- (int)randomNumber {
    return rand();
}
@end

And here's how it could be used:

int main(int argc, char **argv) {
    MyClass *foo = [MyClass create];
    if (foo) {
        printf("random! %i\n", [foo randomNumber]);
        [foo destroy];
    }
}

Edit: If you don't even want to use class_createInstance() and object_dispose(), you'll have to implement equivalents manually, as well as an equivalent of class_getInstanceSize() so you know how much memory an object occupies. But even if you manage that, don't think you've escaped the Objective-C runtime! Message dispatch is still entirely built on the C functions in the runtime, and Objective-C syntax is transformed into calls to those functions during compilation.

How to Stop UIWebView from playing mp3?

10 votes

I am loading a MP3 file into UIWebView control on iPad Application, I have a UIButton called done the user expected to dismiss the UIWebView from loading the music or whatever document, I load the mp3 file as the following:

// points to the mp3 file path
NSURL *url = [NSURL fileURLWithPath:self.sFilePath]; 
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[web loadRequest:request];

When the user hit done I do the following:

[self.webview removeFromSuperview];
[self.webview release];

But that does not stop the music from playing, I noticed that loading mp3 files on UIWebView it open the QuickTime player is that correct? do I need to stop this player?

I am greatly appreciative of any guidance or help.

I suggest that you play the sound yourself using for example AVAudioPlayer (probably the easiest way to play and control sounds in iOS).

Something like this:

NSURL *url = [NSURL fileURLWithPath:self.sFilePath];
NSData *mySound = [NSData dataWithContentsOfURL:url];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithData:mySound error:NULL];
audioPlayer.numberOfLoops = 0;
[audioPlayer play];

You can then stop the sound as simple as:

[audioPlayer stop];

or

[audioPlayer pause];

Don't forget to include the AVFoundation.framework in your project.

iPhone : Unable to understand the following coding.

10 votes

I have downloaded some example coding. But I found strange coding or maybe I have seen it first time.

Can anybody help me to understand following coding?

NSArray *wordStrings = [response.spellingSuggestions wn_map: ^id (id obj) {
    return [obj word];
}];

Let's break it apart, from the inside out.

[obj word]

A message with the selector word to the object whose pointer is in the variable obj.

return [obj word];

A statement returning the value returned by that message.

^id (id obj) {
    return [obj word];
}

Here things get interesting.

This is a block. Let's disassemble it:

  • ^: It's a block!
  • id: Return type. This block returns an object pointer (id).
  • (id obj): Arguments. It takes one, which is the obj variable used as the receiver in the message expression. As we can guess from its name and as is made explicit here, it is also an object pointer.
  • { … }: The body of the block.

So, a block taking one object and returning an object.

[response.spellingSuggestions wn_map: ^id (id obj) {
    return [obj word];
}]

The block is passed to a wn_map: message. Let's drill back inward, at the other end of this message expression:

response.spellingSuggestions

This is actually another message expression. It sends the spellingSuggestions message to the object whose pointer is in the response variable. This sort of expression is called a property access expression, because spellingSuggestions should be a formal property (declared with @property), but ultimately it's just another Objective-C message.

Or response could be a structure and this expression a structure member access, but in modern Objective-C code, that's unlikely. Only you know, since you didn't show the declaration of response. If its type is id or SomeObjectiveCClass *, this is a message expression. If its type is something else, with or without the struct keyword but definitely without an *, then it is a structure member access expression.

Either way, this expression evaluates to an object pointer, presumably an object that somehow encapsulates or lists spelling suggestions.

[response.spellingSuggestions wn_map: ^id (id obj) {
    return [obj word];
}]

… which you then send the wn_map: message to, passing the block. I'd guess that the wn_map: method will call the block for every spelling suggestion…

NSArray *wordStrings = [response.spellingSuggestions wn_map: ^id (id obj) {
    return [obj word];
}];

… and return a pointer to an NSArray, which you initialize the wordStrings variable with.


Incidentally, another way to write this (assuming wn_map: does what I think it does) would have been:

NSArray *wordStrings = [response valueForKeyPath:@"spellingSuggestions.word"];

or:

NSArray *wordStrings = [response.spellingSuggestions valueForKey:@"word"];

The former will do the latter as part of its work (and the former will also use valueForKey: to get response.spellingSuggestions, rather than just sending [response spellingSuggestions] as the original code and the latter revision do).

Assuming spellingSuggestions returns an NSArray, this valueForKey: message to that array will do the same thing as wn_map: and the block: Send the word message to each suggestion, and gather the results into a new array—the one you assign to wordStrings.

9 votes

I'm going through all of my documentation regarding memory management and I'm a bit confused about something.

When you use @property, it creates getters/setters for the object:

.h: @property (retain, nonatomic) NSString *myString

.m: @synthesize myString

I understand that, but where I get confused is the use of self. I see different syntax in different blogs and books. I've seen:

myString = [NSString alloc] initWithString:@"Hi there"];

or

self.myString = [NSString alloc] initWithString:@"Hi there"];

Then in dealloc I see:

self.myString = nil;

or

[myString release];

or

self.myString = nil;
[myString release];

On this site, someone stated that using self adds another increment to the retain count? Is that true, I haven't seen that anywhere.

Do the automatic getters/setters that are provided autorelease?

Which is the correct way of doing all of this?

Thanks!

If you are not using the dot syntax you are not using any setter or getter.

The next thing is, it depends on how the property has been declared.

Let's assume something like this:

@property (nonatomic, retain) Article *article;
...
@synthesize article;

Assigning something to article with

self.article = [[Article alloc] init];

will overretain the instance given back by alloc/init and cause a leak. This is because the setter of article will retain it and will release any previous instance for you.

So you could rewrite it as:

self.article = [[[Article alloc] init] autorelease];

Doing this

article = [[Article alloc] init]; 

is also ok, but could involve a leak as article may hold a reference to an instance already. So freeing the value beforehand would be needed:

[article release];
article = [[Article alloc] init]; 

Freeing memory could be done with

[article release];

or with

self.article = nil;

The first one does access the field directly, no setters/getters involved. The second one sets nil to the field by using a setter. Which will release the current instance, if there is one before setting it to nil.

This construct

self.myString = nil; 
[myString release];

is just too much, it actually sends release to nil, which is harmless but also needless.

You just have to mentally map hat using the dot syntax is using accessor methods:

self.article = newArticle
// is
[self setArticle:newArticle];

and

myArticle = self.article;
// is
myArticle = [self article];

Some suggestions on reading, all official documents by Apple:

The Objective-C Programming Language

Memory Management Programming Guide

iphone+Difference between nil,NIL and null

9 votes

Hi, I am newbie to iphone programming, I'm just in the learning stage. I want to know the difference between nil, NIL and null. I've googled around and found this:

nil -> Null-pointer to objective- c object

NIL -> Null-pointer to objective- c class

null-> null pointer to primitive type or absence of data.

But I'm not able to get the terms objective-c object and class clearly.

Please explain me this and is there any word like NSNULL or NSnil in objective-c? If yes, then please explain for what it is for.

Thanks

nil is the literal null value for Objective-C objects, corresponding to the abstract type id or any Objective-C type declared via @interface. For instance:

NSString *someString = nil;
NSURL *someURL = nil;
id someObject = nil;

if (anotherObject == nil) // do something

Nil is the literal null value for Objective-C classes, corresponding to the type Class. Since most code doesn’t need variables to reference classes, its use is not common. One example is:

Class someClass = Nil;
Class anotherClass = [NSString class];

NULL is the literal null value for arbitrary C pointers. For instance,

int *pointerToInt = NULL;
char *pointerToChar = NULL;
struct TreeNode *rootNode = NULL;

NSNull is a class for objects that represent null. In fact, there’s only one object, namely the one returned by +[NSNull null]. It is different from nil because nil is a literal null value, i.e., it isn’t an object. The single instance of NSNull, on the other hand, is a proper object.

NSNull is often used in Foundation collections since they cannot store nil values. In the case of dictionaries, -objectForKey: returns nil to indicate that a given key has no corresponding object in the dictionary, i.e., the key hasn’t been added to the dictionary. If you want to make it explicit that you have a certain key but it doesn’t have a value yet, you can use [NSNull null].

For instance, the following throws an exception because dictionaries cannot store nil values:

NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:nil forKey:@"someKey"];

On the other hand, the following code is valid since [NSNull null] is a non-nil object:

NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:[NSNull null] forKey:@"someKey"];

It’s worth mentioning that Foundation collections have initialisers that use nil as a marker for the end of a list of objects without having to specify the number of elements in the list. This can only happen because nil cannot be stored in a Foundation collection. For instance,

NSArray *array = [NSArray arrayWithObjects:@"one", @"two", nil];

As for NIL or NSNil, there are no such things in Objective-C or Apple Foundation.

Will Creating new Private Key impact apps which are already on App Store?

8 votes

I have lost my private key and I want to create new one for a new app that I will be submitting soon.

But I also have an app on App Store. If I change my private key, how will it impact that app?

Please let me know.

Thanks!

No problems with doing so. I had to do it about a year ago for a client's app when they couldn't get the key from the previous developer. Just make sure you go in and redo all of the certs and provisioning too.

Core Animation formula for movement

7 votes

I have a formula for setting x and y of an object at every frame. In a classic for (i=0; i < x; i++) loop, I can bind it to the i value and calculate x and y values based on the current value of i that represents the passing of time.

I intended to use it with a NSTimer object and update the coordinate points at every tick, but I've seen that NSTimer is descouraged for animations.

Can I do the same with Core Animation? Instead of the standard "from here to there in given seconds", I would need a method to "update the position with this formula".

If you can model your function with a cubic Bézier curve, you can create a custom CAMediaTimingFunction instance and assign it to the animation's timingFunction property.

If a Bézier curve does not work, a CAKeyframeAnimation might indeed work.

Maintain centre coordinate while pinching MKMapView

7 votes

If you pinch to zoom in/out in Apple's Maps application while tracking the device's location, the "pan" component of the pinch gesture is ignored and the blue location indicator remains fixed in the centre of the screen. This is not the case when using a plain MKMapView.

Assuming I already have the user's location, how could I achieve this effect? I've tried resetting the centre coordinate in the delegate's regionDid/WillChangeAnimated: methods but they're only called at the start and end of the gesture. I also tried adding a UIPinchGestureRecognizer subclass that resets the centre coordinate when the touches move, but this resulted in rendering glitches.


Edit: For those who are interested, the following works for me.

// CenterGestureRecognizer.h
@interface CenterGestureRecognizer : UIPinchGestureRecognizer

- (id)initWithMapView:(MKMapView *)mapView;

@end

// CenterGestureRecognizer.m
@interface CenterGestureRecognizer ()

- (void)handlePinchGesture;

@property (nonatomic, assign) MKMapView *mapView;

@end

@implementation FPinchGestureRecognizer

- (id)initWithMapView:(MKMapView *)mapView {
  if (mapView == nil) {
    [NSException raise:NSInvalidArgumentException format:@"mapView cannot be nil."];
  }

  if ((self = [super initWithTarget:self action:@selector(handlePinchGesture)])) {
    self.mapView = mapView;
  }

  return self;
}

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
  return NO;
}

- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
  return NO;
}

- (void)handlePinchGesture {
  CLLocation *location = self.mapView.userLocation.location;
  if (location != nil) {
    [self.mapView setCenterCoordinate:location.coordinate];
  }
}

@synthesize mapView;

@end

Then simply add it to your MKMapView:

[self.mapView addGestureRecognizer:[[[CenterGestureRecognizer alloc] initWithMapView:self.mapView] autorelease]];

When the user pinches the screen on the actual device (as opposed to the simulator), it causes both a pan and a pinch gesture – the pinch contains the "zoom" element of the motion, and the pan contains the vertical and horizontal change. You need to be intercepting and blocking the pan, and that means using a UIPanGestureRecognizer.

Set scrollEnabled to NO, then add a UIPanGestureRecognizer to reset the center coordinate. The combination will block both single-finger panning and the pan component of a pinch.


Edit to add more details, and after seeing your code: touchesMoved:withEvent is called after the pan has already begun, so if you change the MKMapView's center there, you'll get the herky-jerky rendering problems you've described. What you really need is to create a UIPanGestureRecognizer with a target-action, like so:

    UIPanGestureRecognizer *pan = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didRecognizePan)] autorelease];
    pan.delegate = self;
    [self.mapView addGestureRecognizer:pan];

...and then add a didRecognizePan method to your controller, and do your center-resetting there.

Is calling super in a category the same as calling it in a subclass?

7 votes

Does calling [super init] do the same thing in a category as a subclass? If not, what's the difference?

In order to understand this, it's probably important to understand the way an object is stored during runtime. There is a class object, which holds all the method implementations, and separately, there is a structure with the storage for the instance's variables. All the instances of a class share the one class object.

When you call a method on an instance, the compiler turns that into a call to objc_msgSend; the method implementation is looked up in the class object, and then run with the instance as an argument.

A reference to super takes effect at compile time, not run time. When you write [super someMethod], the compiler turns that into a call to objc_msgSendSuper instead of the usual objc_msgSend. This starts looking for the method implementation in the superclass's class object, rather than the instance's class object.1

A category simply adds methods to the class object; it has little or no relation to subclassing.

Given all that, if you refer to super inside of a category, it does indeed do the same thing that it would inside of a class -- the method implementation is looked up on the current instance's superclass object, and then run with that instance as an argument.

Now, Itai's post answers the question more directly. In code:

@interface Sooper : NSObject {}
- (void) meth;
@end

@interface Sooper ()
- (void) catMeth;
@end

@interface Subb : Sooper {}
- (void) subbMeth;
@end

@interface Subb ()
- (void) catSubbMeth;
@end

@implementation Sooper
- (void) meth {
    [super doIt];    // Looks up doIt in NSObject class object
}

- (void) catMeth {
    [super doIt];    // Looks up doIt in NSObject class object
}
@end

@implementation Subb
- (void) subbMeth {
    [super doIt];    // Looks up doIt in Sooper class object
}

- (void) catSubbMeth {
    [super doIt];    // Looks up doIt in Sooper class object
}
@end

1One important thing to note is that the method doesn't get called on an instance of the superclass. This is where that separation of methods and data comes in. The method still gets called on the same instance in which [super someMethod] was written, i.e., an instance of the subclass, using that instance's data; it just uses the superclass's implementation of the method.

So a call to [super class] goes to the superclass object, finds the implementation of the method named class, and calls it on the instance, transforming it into the equivalent of [self theSuperclassImplementationOfTheMethodNamedClass]. Since all that method does is return the class of the object on which it was called, you don't get the superclass's class, you get the class of the instance. Due to that, calling class is kind of a poor test of this phenomenon.