Objective-C Flashcards

1
Q

What is a selector?

A

A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.

Getting a Selector
Compiled selectors are of type SEL. There are two common ways to get a selector:

At compile time, you use the compiler directive @selector.
SEL aSelector = @selector(methodName);

At runtime, you use the NSSelectorFromString function, where the string is the name of the method:
SEL aSelector = NSSelectorFromString(@”methodName”);
You use a selector created from a string when you want your code to send a message whose name you may not know until runtime.

Using a Selector
You can invoke a method using a selector with performSelector: and other similar methods.

SEL aSelector = @selector(run);
[aDog performSelector:aSelector];
[anAthlete performSelector:aSelector];
[aComputerSimulation performSelector:aSelector];

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What is Run time (program lifecycle phase)?

A

A: the period during which a computer program is executing.

When a program is to be executed, a loader first performs the necessary memory setup and links the program with any dynamically linked libraries it needs, and then the execution begins starting from the program’s entry point. In some cases, a language or implementation will have these tasks done by the language runtime instead, though this is unusual in mainstream languages on common consumer operating systems.

Some program debugging can only be performed (or is more efficient or accurate when performed) at runtime. Logic errors and array bounds checking are examples. For this reason, some programming bugs are not discovered until the program is tested in a production environment with real data, despite sophisticated compile-time checking and pre-release testing. In this case, the end user may encounter a runtime error message.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

What is a Runtime system?

A

A: software designed to support the execution of computer programs.

Most languages have some form of runtime system, which implements control over the order in which work that was specified in terms of the language gets performed. Over the years, the meaning of the term ‘runtime system’ has been expanded to include nearly any behaviors that are dynamically determined during execution.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What is execution?

A

A: Execution in computer and software engineering is the process by which a computer or a virtual machine performs the instructions of a computer program.

The instructions in the program trigger sequences of simple actions on the executing machine. Those actions produce effects according to the semantics of the instructions in the program.

Programs for a computer may execute in a batch process without human interaction, or a user may type commands in an interactive session of an interpreter. In this case the “commands” are simply programs, whose execution is chained together.

The term run is used almost synonymously. A related meaning of both “to run” and “to execute” refers to the specific action of a user starting (or launching or invoking) a program, as in “Please run the application.”

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What is the Objective-C implementation section?

A

A: the @implementation section contains the actual code for the methods you declared in the @interface section.

You have to specify what type of data is to be stored in the objects of this class. That is, you have to describe the data that members of the class will contain. These members are called the instance variables. Just as a point of terminology, you say that you declare the methods in the @interface section and that you define them (that is, give the actual code) in the @implementation section.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Explain method swizzling. When you would use it?

A

A: Method swizzling is the process of changing the implementation of an existing selector. Most of the use cases found for method swizzling involve extending the functionality of an existing method. That is, there is some method that you can’t modify directly, but would like to add additional functionality to (e.g., logging, etc.).

(Look up example of the code on internet)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Take three objects: a grandparent, parent and child. The grandparent retains the parent, the parent retains the child and the child retains the parent. The grandparent releases the parent. Explain what happens

A

Unless there is some other reference to the parent or child, they both become orphaned. But the retain cycle between the parent and child prevent either from being released and they become wasted memory.

Here The “Grandparent” retains the “parent” and “parent” retains the “child” where as “child” retains the “parent.” Here a retain cycle is established between parent and child. After releasing the Grandparent both the parent and child become orphaned but the retain count of parent will not be zero as it is being retained by the child and hence causes a memory management issue.

There are two possible solutions:

1) Use weak pointer to parent , i.e a child should be using weak reference to parent, which is not retained.
2) Use “close” methods to break retain cycles.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What happens when you invoke a method on a nil pointer?

A

A message sent to a nil object is perfectly acceptable in Objective-C, it’s treated as a no operation (a computer instruction that takes up a small amount of space but specifies no operation. The computer processor simply moves to the next sequential instruction. The no op is included in most assembler languages.) There is no way to flag it as an error because it’s not an error, in fact it can be a very useful feature of the language.

In Objective-C, it is valid to send a message to nil—it simply has no effect at runtime. There are several patterns in Cocoa that take advantage of this fact. The value returned from a message to nil may also be valid:

1) If the method returns an object, then a message sent to nil returns 0 (nil), for example:

Person *motherInLaw = [[aPerson spouse] mother];

If aPerson’s spouse is nil, then mother is sent to nil and the method returns nil.

2) If the method returns any pointer type, any integer scalar of size less than or equal to sizeof(void*), a float, a double, a long double, or a long long, then a message sent to nil returns 0.
3) If the method returns a struct, as defined by the Mac OS X ABI Function Call Guide to be returned in registers, then a message sent to nil returns 0.0 for every field in the data structure. Other struct data types will not be filled with zeros.
4) If the method returns anything other than the aforementioned value types the return value of a message sent to nil is undefined.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Give two separate and independent reasons why retainCount should never be used in shipping code.

A

Reasons:

1) The absolute retain count of an object may change at any time once an object has been passed through any system API. This makes retainCount especially unpredictable and therefore useless in a group project setting.
2) Autorelease is a per-thread concept whereas retain counts are global; race condition derived hilarity can easily ensue. Thus, retain count is at the mercy of something you have no control over (multi-threading race conditions related to app conditions and the hardware the app is running on) and is different each time the app is used.

You should never use -retainCount, because it never tells you anything useful. The implementation of the Foundation and AppKit/UIKit frameworks is opaque; you don’t know what’s being retained, why it’s being retained, who’s retaining it, when it was retained, and so on.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Explain your process for tracing and fixing a memory leak

A

First: Set the NSZombieEnabled argument in your executable options, which sometimes helps narrow down the cause
Second: Run with Apple Instruments such as Leaks to look for memory issues
Third: Set a breakpoint in your code and step through until you narrow down where it’s leaking
Fourth: Zone in on ‘common leaks.’
Example 1
Forgetting to call release in the dealloc method on a retained object.
Example 2
@property (nonatomic, retain) MyClass *objectA;
self.objectA = [[MyClass alloc] init]; //This does 2 retains on objectA, one for calling self.objectA which uses the ‘retain’ property modifier, and one for calling alloc. When [objectA release] is called in the dealloc method, there is still a retain on objectA, but nothing will point to it anymore resulting in a leak.

(from Ray Wenderlich’s tutorial on using instruments for debugging memory leaks)
http://www.raywenderlich.com/2696/instruments-tutorial-for-ios-how-to-debug-memory-leaks

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is the purpose of an object’s properties?

A

An object’s properties let other objects inspect or change its state.

But, in a well-designed object-oriented program, it’s not possible to directly access the internal state of an object. Instead, accessor methods (getters and setters) are used as an abstraction for interacting with the object’s underlying data.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Explain how an autorelease pool works at the runtime level.

A
Each thread (including the main thread) maintains its own stack of NSAutoreleasePool objects (see “Threads”). As new pools are created, they get added to the top of the stack. When pools are deallocated, they are removed from the stack. Autoreleased objects are placed into the top autorelease pool for the current thread. When a thread terminates, it automatically drains all of the autorelease pools associated with itself.
The concept of an autorelease pool is simple, whenever an object instance is marked as autoreleased (for example NSString* str = [[[NSString alloc] initWithString:@"hello"] autorelease];), it will have a retain count of +1 at that moment in time, but at the end of the run loop, the pool is drained, and any object marked autorelease then has its retain count decremented. It's a way of keeping an object around while you prepare whatever will retain it for itself.
Every time -autorelease is sent to an object, it is added to the inner-most autorelease pool. When the pool is drained, it simply sends -release to all the objects in the pool.
Autorelease pools are simply a convenience that allows you to defer sending -release until "later". That "later" can happen in several places, but the most common in Cocoa GUI apps is at the end of the current run loop cycle.

Read this for more detailed explanation and graphics:
http://asgteach.com/2011/06/ios-memory-management-using-autorelease/

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

When dealing with property declarations, what is the difference between atomic and non-atomic?

A

Atomic:
• is the default behavior
• will ensure the present process is completed by the CPU, before another process accesses the variable
• is not fast, as it ensures the process is completed entirely

Non-Atomic:
• is NOT the default behavior
• faster (for synthesized code, that is, for variables created using @property and @synthesize)
• not thread-safe
• may result in unexpected behavior, when two different process access the same variable at the same time

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

In C, how would you reverse a string as quickly as possible?

A

Using STL:

std::reverse from works for strings and char arrays.

string str = “Hello”;
char chx[] = “Hello”;

reverse(str.begin(), str.end());
reverse(chx, chx + strlen(chx));

cout

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Which is faster: to iterate through an NSArray or an NSSet?

A

When the order of the items in the collection is not important, sets offer better performance for finding items in the collection.

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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Explain how code signing works

A
  1. Check your public/private key pair, name them for future peace of mind. (warning sign: more than one pair…)
  2. Create your developer certificate using Keychain Access to generate a certificate request. Download the certificate and double click to install. Verify that you see it in your keychain.
  3. Download the Apple Worldwide Developer Relations Certification Authority Certificate. Double click to install it, verify that you see it in your keychain.
  4. Check your project’s Bundle ID and go and create an App ID for your app through the Provisioning Portal. The Bundle ID must match.
  5. Get all the UDIDs for the devices you want to build for added to your devices list in the Provisioning Portal. These must match. Cut and paste of these 40-digit strings is highly recommended, too easy to make mistakes otherwise.
  6. Create a Provisioning Profile specifying the certificates, the app ID and the UDIDs you want this profile to support.
  7. Download, then drag the profile into Xcode’s Organizer window, under the Library section for Provisioning Profiles.
17
Q

What is posing in Objective-C?

A

Objective-C permits a class to wholly replace another class within a program. The replacing class is said to “pose as” the target class.

For the versions that supported posing, all messages sent to the target class are instead received by the posing class.

NSObject contains the poseAsClass: method that enables us to replace the existing class as said above.

Note that Posing was declared deprecated in Mac OS X 10.5 and it’s not available for use thereafter. So for those who are not concerned about these deprecated methods can skip this chapter.

18
Q

List six instruments that are part of the standard.

A

Activity Monitor - The Activity Monitor instrument captures information about the load on the system measured against the virtual memory size. It can record information from a single process or from all processes running on the system.

Allocations - The Allocations instrument captures information about memory allocation for an app. It records information from a single process only.
The Allocations instrument is associated with the following tasks: Recovering Memory You Have Abandoned,
Finding Leaks in Your App, Eradicating Zombies with the Zombies Trace Template.

Automation - You can use the Automation instrument to automate user interface tests in your iOS app through test scripts that you write.

Energy Diagnostics - The Energy Usage instrument captures information about energy usage on a device since start up.The Energy Usage instrument is associated with the following tasks: Saving Energy with the Energy Diagnostics Trace Template.

Leaks - Use the Leaks instrument of the Instruments analysis tool to find objects in your app that are no longer referenced and reachable.

Network - The Network Activity Monitor instrument captures information about the system’s network traffic. It can record information from a single process or from all processes running on the system.

Zombies - The Zombies profiling template uses the Allocations instrument to measure general memory usage in your app, with a focus on the detection of overreleased “zombie” objects—that is, objects that are called after they’ve been released and no longer exist.

19
Q

What does the copy property do and how does it work?

A

The copy modifier creates a clone of the object- a new pointer to a new object at a new address in the memory. This sets the internal object pointer to the copy of the passed object.

NSMutableString *mutString = [NSMutableString stringWithString:@”ABC”];
NSString *b = [mutString retain];
[mutString appendString:@”Test”];
At this point b was just modified by the 3rd line.

NSMutableString *mutString = [NSMutableString stringWithString:@”ABC”];
NSString *b = [mutString copy];
[mutString appendString:@”Test”];
In this case b is the original string, and isn’t modified by the 3rd line.

This applies for all mutable types.

20
Q

What does the retain property do?

A

It claims ownership of the object and increases the retain count. A pre-ARC attribute. You will have to manually release the object to decrease its retain count (which will release it from memory when the retain count goes to 0). You should not use this in an ARC project.

21
Q

For a UIView, what is the difference between frames and bounds?

A

The BOUNDS of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to its own coordinate system (0,0). Bounds are used when placing the view’s content or subviews within itself

The FRAME of an UIView is the rectangle, expressed as a location (x,y) and size (width,height) relative to the superview it is contained within. Frame is used when placing the view in the parent.

22
Q

What happens when the following code executes?

Ball *ball = [[[[Ball alloc] init] autorelease] autorelease];

A

Let’s break it down:

[Ball alloc init]: This initializes the Ball object we just created.

[[Ball alloc init] autorelease]: This adds the Ball to the current autorelease pool, so it will be released when that pool is drained. This is the right thing to do if, for example, we were going to return the Ball from a method.

[[[Ball alloc init] autorelease] autorelease]: This autoreleases the Ball object again. This is 100% wrong. alloc is the only claim to ownership that we need to balance, so the Ball will now be released too many times. This could manifest in any number of ways, but it will probably just crash.

23
Q

List the five iOS app states.

A

1) Not running -: The app has not been launched or was running but was terminated by the system.
2) Suspended -: The app is in the background, but no code is being executed
3) Background -: The app is running in the background, and executing code.
4) Inactive -: The app is running in the foreground, but not receiving events. An iOS app can be placed into an inactive state, for example, when a call or SMS message is received.
5) Active -: The app is running in the foreground, and receiving events.

24
Q

Consider the following UITableViewCell constructor. What is the purpose of the reuseIdentifier? What is the advantage of setting it to a non-nil value?

A

The reuseIdentifier is used to group together similar rows in an UITableView; i.e., rows that differ only in their content, but otherwise have similar layouts.

A UITableView will normally allocate just enough UITableViewCell objects to display the content visible in the table. If reuseIdentifier is set to a non-nil value, then when the table view is scrolled, UITableView will first attempt to reuse an already allocated UITableViewCell with the same reuseIdentifier. If reuseIdentifier has not been set, the UITableView will be forced to allocate new UITableViewCell objects for each new item that scrolls into view, potentially leading to laggy animations.

25
Q

What are different ways that you can specify the layout of elements in a UIView?

A

Here are a few common ways to specify the layout of elements in a UIView:

Using InterfaceBuilder, you can add a XIB file to your project, layout elements within it, and then load the XIB in your application code (either automatically, based on naming conventions, or manually). Also, using InterfaceBuilder you can create a storyboard for your application.
You can your own code to use NSLayoutConstraints to have elements in a view arranged by Auto Layout.
You can create CGRects describing the exact coordinates for each element and pass them to UIView’s - (id)initWithFrame:(CGRect)frame method.

26
Q

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
A

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;

@end
A 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.

27
Q

Identify the bug in the following code:

@interface TTWaitController : UIViewController

@property (strong, nonatomic) UILabel *alert;

@end

@implementation TTWaitController

  • (void)viewDidLoad
    {
    CGRect frame = CGRectMake(20, 200, 200, 20);
    self.alert = [[UILabel alloc] initWithFrame:frame];
    self.alert.text = @”Please wait 10 seconds…”;
    self.alert.textColor = [UIColor whiteColor];
    [self.view addSubview:self.alert];NSOperationQueue *waitQueue = [[NSOperationQueue alloc] init];
    [waitQueue addOperationWithBlock:^{
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    self.alert.text = @”Thanks!”;
    }];
    }

@end

@implementation TTAppDelegate

  • (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = [[TTWaitController alloc] init];
    [self.window makeKeyAndVisible];
    return YES;
    }
    How could you fix this issue?
A

When the above code dispatches work using NSOperationQueue’s method addOperationWithBlock, there is no guarantee that the block being enqueued will be executed on the main thread. Notice that the content of the UILabel is being updated within the body of the block. UI updates that are not executed on the main thread can lead to undefined behavior. This code might appear to be working correctly for a long time before anything goes wrong, but UI updates should always happen on the main thread.

The easiest way to fix the potential issue is to change the body of the block so that the update is re-enqueued using the main thread’s queue as follows:

[waitQueue addOperationWithBlock:^{
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.alert.text = @”Thanks!”;
}];
}];

28
Q

What’s the difference between an “app ID” and a “bundle ID” and what is each used for?

A

An App ID is a two-part string used to identify one or more apps from a single development team. The string consists of a Team ID and a bundle ID search string, with a period (.) separating the two parts. The Team ID is supplied by Apple and is unique to a specific development team, while the bundle ID search string is supplied by teh developer to match either the bundle ID of a single app or a set of bundle IDs for a group of apps.

Because most people think of the App ID as a string, they think it is interchangeable with Bundle ID. It appears this way because once the App ID is created in the Member Center, you only ever use the App ID Prefix which matches the Bundle ID of the Application Bundle.

The bundle ID uniquely defines each App. It is specified in Xcode. A single Xcode project can have multiple Targets and therefore output multiple apps. A common use case for this is an app that has both lite/free and pro/full versions or is branded multiple ways.

Bundle ID Example: com.hivistamedia.fitness
App ID Example: 974999670

29
Q

What are “strong” and “weak” references? Why are they important and how can they be used to help control memory management and avoid memory leaks?

A

This is also a default attribute, and must be overridden if you want to change it. In ARC, its opposite is the “weak” attribute. I started post-ARC, so my first-hand knowledge is better with strong and weak, compared to the pre-ARC ones listed later. Strong is generally used by a class to establish ownership of an object. It increases the retain count (something ARC deals with for you), it basically keeps the object that is pointed to in memory until that class instance stops pointing to it. This is usually what you want, but there it can cause something called a “retain cycle.” The weak attribute helps solve this issue.

This gives a pointer to an object, but does not claim ownership, and does not increase the retain count. It basically keeps a valid pointer to an object as long as another class points to it strongly. If nothing else is trying to retain it, the weak pointer is automatically set to nil. An example where this would be useful is if you had two classes, one for a petOwner, and one for their pet. Lets say for some reason we want them to refer to each other, so you can request the pet of an owner, or an owner of a pet. If the pet’s petOwner property, and the petOwner’s pet property were both strong, the memory could never be released because they would both be telling ARC that they both need it. If we set the petOwner’s pet property to weak, then we avoid the retain cycle. If the pet object is destroyed, while the petOwner still has a reference to it, the petOwner’s pet property will be automatically set to nil.

Reciprocal strong references between objects should therefore be avoided to the extent possible. However, when they are necessary, a way to avoid this type of memory leak is to employ weak references. Declaring one of the two references as weak will break the retain cycle and thereby avoid the memory leak.

To decide which of the two references should be weak, think of the objects in the retain cycle as being in a parent-child relationship. In this relationship, the parent should maintain a strong reference (i.e., ownership of) its child, but the child should not maintain maintain a strong reference (i.e., ownership of) its parent.

For example, if you have Employer and Employee objects, which reference one another, you would most likely want to maintain a strong reference from the Employer to the Employee object, but have a weak reference from the Employee to the Employer.

30
Q

Describe managed object context and the functionality that it provides.

A

A managed object context (represented by an instance of NSManagedObjectContext) is basically a temporary “scratch pad” in an application for a (presumably) related collection of objects. These objects collectively represent an internally consistent view of one or more persistent stores. A single managed object instance exists in one and only one context, but multiple copies of an object can exist in different contexts.

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, though, the persistent store remains unchanged.

Key functionality provided by a managed object context includes:

Life-cycle management. The context provides validation, inverse relationship handling, and undo/redo. Through a context you can retrieve or “fetch” objects from a persistent store, make changes to those objects, and then either discard the changes or commit them back to the persistent store. The context is responsible for watching for changes in its objects and maintains an undo manager so you can have finer-grained control over undo and redo. You can insert new objects and delete ones you have fetched, and commit these modifications to the persistent store.
Notifications. A context posts notifications at various points which can optionally be monitored elsewhere in your application.
Concurrency. Core Data uses thread (or serialized queue) confinement to protect managed objects and managed object contexts. In OS X v10.7 and later and iOS v5.0 and later, when you create a context you can specify the concurrency pattern with which you will use it using initWithConcurrencyType:.

For more information, see the iOS Developer Library Core Data Basics or the NSManagedObjectContext reference.

31
Q

Reverse a C string as quickly as possible WITHOUT allocating memory. Also, how would you do it using XOR.

A

Without allocating memory:

int length = strlen(string);
for(int i = 0; i

32
Q

Compare and contrast the different ways of achieving concurrency in OS X and iOS.

A

There are basically three ways of achieving concurrency in iOS:

threads
dispatch queues
operation queues
The disadvantage of threads is that they relegate the burden of creating a scalable solution to the developer. You have to decide how many threads to create and adjust that number dynamically as conditions change. Also, the application assumes most of the costs associated with creating and maintaining the threads it uses.

OS X and iOS therefore prefer to take an asynchronous design approach to solving the concurrency problem rather than relying on threads.

One of the technologies for starting tasks asynchronously is Grand Central Dispatch (GCD) that relegates thread management down to the system level. All the developer has to do is define the tasks to be executed and add them to the appropriate dispatch queue. GCD takes care of creating the needed threads and scheduling tasks to run on those threads.

All dispatch queues are first-in, first-out (FIFO) data structures, so tasks are always started in the same order that they are added.

An operation queue is the Cocoa (API for OSX) equivalent of a concurrent dispatch queue and is implemented by the NSOperationQueue class. Unlike dispatch queues, operation queues are not limited to executing tasks in FIFO order and support the creation of complex execution-order graphs for your tasks.

33
Q

Will the code below log “areEqual” or “areNotEqual”? Explain your answer.

NSString *firstUserName = @”nick”;
NSString *secondUserName = @”nick”;

if (firstUserName  == secondUserName)
{
  NSLog(@"areEqual");
}
else
{
  NSLog(@"areNotEqual");
}
A

The code will output “areEqual”.

While one might think this is obvious, it’s not. Here’s why:

Comparing pointer values equates to checking if they point to the same object. Pointers will have the same value if and only if they actually point to the exact same object (whereas pointers to different objects will not have the same value, even if the objects they point to have the same value).

In the above code snippet, firstUserName and secondUserName are each pointers to string objects. One could easily assume that they are pointing to different string objects, despite the fact that the objects that they point to both have the same value. However, the iOS compiler optimizes references to string objects that have the same value (i.e., it reuses them rather than allocating identical string objects redundantly), so both pointers are in fact pointing to same address and the condition therefore evaluates to true.