Objective-C is a nice middle ground that gets close to the performance of compiled languages (like C++) while still maintaining some dynamism that you find in interpreted languages (like JavaScript or Ruby). There is still some Objective-C development going on so if you want to work in the iOS dev area, then you will need to know both Swift and Objective-C. Follow along and check 27 most common Objective-C interview questions and answers every experienced iOS and macOS developer should know.
A formal protocol declares a list of methods that client classes are expected to implement. Formal protocols have their own declaration, adoption, and type-checking syntax. You can designate methods whose implementation is required or optional with the @required and @optional keywords. Subclasses inherit formal protocols adopted by their ancestors. A formal protocol can also adopt other protocols. Formal protocols are an extension to the Objective-C language.
An informal protocol is a category on NSObject, which implicitly makes almost all objects adopters of the protocol. (A category is a language feature that enables you to add methods to a class without subclassing it.) Implementation of the methods in an informal protocol is optional. Before invoking a method, the calling object checks to see whether the target object implements it. Until optional protocol methods were introduced in Objective-C 2.0, informal protocols were essential to the way Foundation and AppKit classes implemented delegation.
NSArray to a string in Objective-C?NSString * result = [[array valueForKey:@"description"] componentsJoinedByString:@""];Blocks are a way of defining a single task or unit of behavior without having to write an entire Objective-C class. Under the covers Blocks are still Objective C objects. They are a language level feature that allow programming techniques like lambdas and closures to be supported in Objective-C. Creating a block is done using the ^ { } syntax:
myBlock = ^{
NSLog(@"This is a block");
}It can be invoked like so:
myBlock();It is essentially a function pointer which also has a signature that can be used to enforce type safety at compile and runtime. For example you can pass a block with a specific signature to a method like so:
- (void)callMyBlock:(void (^)(void))callbackBlock;If you wanted the block to be given some data you can change the signature to include them:
- (void)callMyBlock:(void (^)(double, double))block {
...
block(3.0, 2.0);
}A protocol is similar to an interface from Java. It defines a list of required and optional methods that a class must/can implement if it adopts the protocol. Any class can implement a protocol and other classes can then send messages to that class based on the protocol methods without it knowing the type of the class.
@protocol MyCustomDataSource
- (NSUInteger)numberOfRecords;
- (NSDictionary *)recordAtIndex:(NSUInteger)index;
@optional
- (NSString *)titleForRecordAtIndex:(NSUInteger)index;
@endA common use case is providing a DataSource for UITableView or UICollectionView.
copy and retain?In a general setting, retaining an object will increase its retain count by one. This will help keep the object in memory and prevent it from being blown away. What this means is that if you only hold a retained version of it, you share that copy with whomever passed it to you.
Copying an object, however you do it, should create another object with duplicate values. Think of this as a clone. You do NOT share the clone with whomever passed it to you.
Consider:
@interface HelloWorldController : UIViewController
@property (strong, nonatomic) UILabel *alert;
@end
@implementation HelloWorldController
- (void)viewDidLoad {
CGRect frame = CGRectMake(150, 150, 150, 50);
self.alert = [[UILabel alloc] initWithFrame:frame];
self.alert.text = @"Hello...";
[self.view addSubview:self.alert];
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
sleep(10);
self.alert.text = @"World";
}
);
}
@endAll UI updates must be performed in the main thread. The global dispatch queue does not guarantee that the alert text will be displayed on the UI. As a best practice, it is necessary to specify any updates to the UI occur on the main thread, as in the fixed code below:
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
sleep(10);
dispatch_async(dispatch_get_main_queue(), ^{
self.alert.text = @"World";
});
});NSArray in Objective-C?For reversing a mutable array, you can add the following category to your code:
@implementation NSMutableArray (Reverse)
- (void)reverse {
if ([self count] <= 1)
return;
NSUInteger i = 0;
NSUInteger j = [self count] - 1;
while (i < j) {
[self exchangeObjectAtIndex:i
withObjectAtIndex:j];
i++;
j--;
}
}
@endYou can also take advantage of the built-in reverseObjectEnumerator method on NSArray, and the allObjects method of NSEnumerator:
NSArray* reversedArray = [[startArray reverseObjectEnumerator] allObjects];Advantages:
Disadvantages:
Key-Value-Coding (KVC) means accessing a property or value using a string.
id someValue = [myObject valueForKeyPath:@"foo.bar.baz"];Which could be the same as:
id someValue = [[[myObject foo] bar] baz];Key-Value-Observing (KVO) allows you to observe changes to a property or value.
To observe a property using KVO you would identify to property with a string; i.e., using KVC. Therefore, the observable object must be KVC compliant.
[myObject addObserver:self forKeyPath:@"foo.bar.baz" options:0 context:NULL];Consider:
#import "TTAppDelegate.h"
@interface TTParent : NSObject
@property (atomic) NSMutableArray *children;
@end
@implementation TTParent
@end
@interface TTChild : NSObject
@property (atomic) TTParent *parent;
@end
@implementation TTChild
@end
@implementation TTAppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
TTParent *parent = [[TTParent alloc] init];
parent.children = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; i++) {
TTChild *child = [[TTChild alloc] init];
child.parent = parent;
[parent.children addObject:child];
}
return YES;
}
@endWhat is the bug in this code and what is its consequence? How could you fix it?
This is a classic example of a retain cycle. The parent will retain the children array, and the array will retain each TTChild object added to it. Each child object that is created will also retain its parent, so that even after the last external reference to parent is cleared, the retain count on parent will still be greater than zero and it will not be removed.
In order to fix this, the child’s reference back to the parent needs to be declared as a weak reference as follows:
@interface TTChild : NSObject
@property (weak, atomic) TTParent *parent;
@endA weak reference will not increment the target’s retain count, and will be set to nil when the target is finally destroyed.
Note:
For a more complicated variation on this question, you could consider two peers that keep references to each other in an array. In this case, you will need to substitute NSArray/NSMutableArray with an NSPointerArray declared as:
NSPointerArray *weakRefArray = [[NSPointerArray alloc] initWithOptions: NSPointerFunctionsWeakMemory];since NSArray normally stores a strong reference to its members.
NSManagedObjectContext in Objective-C and how does it work?You can think of a managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad where they form an object graph (or a collection of object graphs). You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered.
NSThread creates a new low-level thread which can be started by calling the start method.
NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(myThreadMainMethod:)
object:nil];
[myThread start]; NSOperationQueue allows a pool of threads to be created and used to execute NSOperations in parallel. NSOperations can also be run on the main thread by asking NSOperationQueue for the mainQueue.
NSOperationQueue* myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperation:anOperation];
[myQueue addOperationWithBlock:^{
/* Do something. */
}];GCD or Grand Central Dispatch is a modern feature of Objective-C that provides a rich set of methods and API's to use in order to support common multi-threading tasks. GCD provides a way to queue tasks for dispatch on either the main thread, a concurrent queue (tasks are run in parallel) or a serial queue (tasks are run in FIFO order).
dispatch_queue_t myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myQueue, ^{
printf("Do some work here.\n");
});atomic and nonatomic attributes?What do atomic and nonatomic mean in property declarations?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;What is the operational difference between these three?
Atomic
Non-Atomic
Suppose there is an atomic string property called "name", and if you call [self setName:@"A"] from thread A, call [self setName:@"B"] from thread B, and call [self name] from thread C, then all operations on different threads will be performed serially which means if one thread is executing a setter or getter, then other threads will wait.
If the property "name" was nonatomic, then all threads in above example - A,B, C and D will execute simultaneously producing any unpredictable result. In case of atomic, either one of A, B or C will execute first, but D can still execute in parallel.
NSArray vs NSSet?NSArray is faster than NSSet for simply holding and iterating. As little as 50% faster for constructing and as much as 500% faster for iterating. So if you only need to iterate contents, don't use an NSSet.
Of course, if you need to test for inclusion, work hard to avoid NSArray. The reason is that a set uses hash values to find items (like a dictionary) while an array has to iterate over its entire contents to find a particular object. Even if you need both iteration and inclusion testing, you should probably still choose an NSSet. If you need to keep your collection ordered and also test for inclusion, then you should consider keeping two collections (an NSArray and an NSSet), each containing the same objects.
If you are adding functions, but not data, use a category. An example of this is adding functions to NSMutableData which allow you to remove X bytes from a section of the data, or remove all BUT X bytes from the data. It doesn't make sense to create an entire sub-class simply to add these two functions, nor does it makes sense to write functions that aren't attached to a class (a plain C function). This allows you to attach the functionality to the class without creating a new, uneeded relationship, and doesn't change any part of existing functionality.
If you need to add/change data and add functionality to manipulate that data, or change functionality to represent a sub-type of object in your controller model, then you sub-class. For example, NSMutableData is a sub-class because it still uses NSData accessors, however, it changes the data representation internally so it can also manipulate the data. In this case a sub-class makes sense because it is no longer NSData, it is a /mutable/ NSData object (new keyword added to describe the object).
nil pointer?@autoreleasepool?NSMapTable vs NSDictionary?nil means and how is it actually useful?NSThread or NSOperationQueue?Rust has been Stack Overflow’s most loved language for four years in a row and emerged as a compelling language choice for both backend and system developers, offering a unique combination of memory safety, performance, concurrency without Data races...
Clean Architecture provides a clear and modular structure for building software systems, separating business rules from implementation details. It promotes maintainability by allowing for easier updates and changes to specific components without affe...
Azure Service Bus is a crucial component for Azure cloud developers as it provides reliable and scalable messaging capabilities. It enables decoupled communication between different components of a distributed system, promoting flexibility and resili...