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.
Explain how code signing works
- Check your public/private key pair, name them for future peace of mind. (warning sign: more than one pair…)
- 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.
- Download the Apple Worldwide Developer Relations Certification Authority Certificate. Double click to install it, verify that you see it in your keychain.
- 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.
- 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.
- Create a Provisioning Profile specifying the certificates, the app ID and the UDIDs you want this profile to support.
- Download, then drag the profile into Xcode’s Organizer window, under the Library section for Provisioning Profiles.
What is posing in Objective-C?
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.
List six instruments that are part of the standard.
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.
What does the copy property do and how does it work?
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.
What does the retain property do?
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.
For a UIView, what is the difference between frames and bounds?
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.
What happens when the following code executes?
Ball *ball = [[[[Ball alloc] init] autorelease] autorelease];
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.
List the five iOS app states.
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.
Consider the following UITableViewCell constructor. What is the purpose of the reuseIdentifier? What is the advantage of setting it to a non-nil value?
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.