Objective-C Flashcards
What is a selector?
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];
What is Run time (program lifecycle phase)?
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.
What is a Runtime system?
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.
What is execution?
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.”
What is the Objective-C implementation section?
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.
Explain method swizzling. When you would use it?
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)
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
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.
What happens when you invoke a method on a nil pointer?
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.
Give two separate and independent reasons why retainCount should never be used in shipping code.
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.
Explain your process for tracing and fixing a memory leak
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
What is the purpose of an object’s properties?
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.
Explain how an autorelease pool works at the runtime level.
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/
When dealing with property declarations, what is the difference between atomic and non-atomic?
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
In C, how would you reverse a string as quickly as possible?
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
Which is faster: to iterate through an NSArray or an NSSet?
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.