How-To-Learn Objective-C Coding Roadmap - Computer Engineering
Framework: How-To-Learn Objective-C Coding Roadmap - Computer Engineering
by Mavericks-for-Alexander-the-Great(ATG)
by Mavericks-for-Alexander-the-Great(ATG)
Learning Objective-C for iOS app development when you are already familiar with Swift's structure and elements can be quite a challenging but rewarding endeavor, as it broadens your capabilities as a developer. Here's a structured approach to learning Objective-C based on the Swift language guide elements you are familiar with:
The Basics and Lexical Structure: Start with the syntax and basic concepts of Objective-C, such as variables, data types, and constants. Objective-C has a different syntax for variable declaration and requires the understanding of pointers, which are less emphasized in Swift.
Functions and Methods: In Objective-C, functions are global and methods are associated with classes. Understand the message syntax, which uses square brackets [], as opposed to Swift’s dot syntax.
Classes and Structures: Objective-C uses header (*.h) and implementation (*.m) files for classes, unlike Swift's single-file approach. Study how classes are defined and how inheritance works, keeping in mind that all Objective-C objects inherit from the NSObject class.
Properties and Variables: Learn how properties are declared in Objective-C with attributes such as nonatomic, strong, weak, readonly, and readwrite, and compare them with Swift's property declarations.
Control Flow: Although control flow elements such as loops and conditionals are similar in concept to Swift, their syntax differs. Become familiar with Objective-C’s for, while, and if statements.
Collection Types: Objective-C uses NSArray, NSSet, and NSDictionary as its primary collection types. Understand their mutable and immutable variants and how they differ from Swift's Array, Set, and Dictionary.
Error Handling and Exception: Objective-C uses a different mechanism for error handling, involving NSError objects and the @try, @catch, and @finally constructs, which are not present in Swift.
Memory Management: Objective-C relies on reference counting for memory management. Learn about Automatic Reference Counting (ARC) and manual retain-release (MRR) concepts, which are critical for Objective-C but abstracted away in Swift.
Dynamic Libraries Support: Objective-C does not support modules the way Swift does. Understand how to link against frameworks and dynamic libraries in Objective-C.
Advanced Concepts: Once comfortable with the basics, delve into advanced topics like blocks (Objective-C’s version of Swift closures), protocols, categories (similar to Swift extensions), and generics.
Community Support: Engage with the Objective-C community. Even though it’s older, there are many experienced developers and extensive resources available. Look for Objective-C projects on GitHub, and participate in forums and discussions.
Coding Conventions and Best Practices: It's important to write clean, maintainable code. Learn about the established coding conventions for Objective-C, which may differ from Swift's.
Here are some additional tips:
Translate Swift code snippets into Objective-C to understand the differences.
Write small iOS apps or components in Objective-C to practice.
Refer to the official Apple documentation for Objective-C, which is comprehensive and well-maintained.
Explore open-source Objective-C projects to see how professional Objective-C code is written.
Keep in mind that while Objective-C is still used, it’s being replaced by Swift in many areas, so balance your learning based on your development needs.
By following the structure of the Swift language guide, you can systematically approach learning Objective-C by drawing parallels and understanding the differences in concepts, syntax, and best practices.
________
When transitioning from Swift to Objective-C, it's helpful to frame your learning within the context of Swift concepts you're already familiar with. Here’s a more detailed framework, broken down by key concepts and their Objective-C counterparts:
Fundamentals
Syntax Basics: Contrast Objective-C's verbose syntax with Swift's more concise one. For instance, explore how if statements and loops are structured differently.
Variables and Data Types: Understand how to declare and use primitives, objects (with * for pointers), and collections. Compare NSArray and NSDictionary with Swift's Array and Dictionary.
Functions vs. Methods: Objective-C distinguishes between functions (C-style, defined outside of classes) and methods (defined within @interface and @implementation). Translate Swift functions into Objective-C method declarations.
Object-Oriented Programming
Classes and Objects: Dive into the .h and .m file structure. Create classes in Objective-C, paying attention to inheritance from NSObject.
Properties: Learn property attributes (e.g., assign, retain, copy, and nonatomic) and compare them with Swift's property wrappers.
Memory Management: Practice with ARC in Objective-C. While Swift also uses ARC, Objective-C requires a deeper understanding of memory management, especially with non-ARC code.
Advanced Topics
Protocols and Delegates: Understand how Objective-C uses protocols and delegates for communication between objects, analogous to Swift's protocol-delegate pattern.
Blocks: These are Objective-C’s version of Swift closures. Practice converting Swift closures to Objective-C blocks.
Error Handling: Study the use of NSError and the pattern of passing errors by reference, as well as exception handling with @try, @catch, and @finally.
Collections and Control Structures
Collections: Get hands-on experience with NSArray, NSDictionary, and their mutable counterparts. Learn the differences in iteration and element access compared to Swift.
Control Flow: Translate Swift control flow constructs into Objective-C. Pay particular attention to looping constructs, which can look quite different.
Modern Objective-C Features
Literals: Objective-C has adopted modern features like array and dictionary literals, and number boxing with @.
Type Annotations: Explore how to use type annotations in Objective-C for collections and blocks.
Modules and Libraries: Understand how to use and create dynamic libraries, as well as importing and using modules with @import.
Development Environment
Xcode: Get familiar with Xcode’s Objective-C support, including the build process, debugging, and profiling tools.
Community and Resources: Locate Objective-C communities for support. Websites like Stack Overflow, GitHub, and Apple Developer Forums can be excellent resources.
Practice and Application
Translate Swift Code: Regularly take Swift code snippets and translate them into Objective-C to solidify your understanding.
Small Projects: Build small projects or components entirely in Objective-C to practice the concepts you've learned.
Read Objective-C Code: Study open-source projects written in Objective-C to gain insights into best practices and more complex use cases.
This structured approach should guide your learning process, helping you build a strong foundation in Objective-C based on your Swift knowledge. Remember that while many concepts have direct analogues, Objective-C has its own idioms and practices that you'll need to embrace to become proficient.
________
I'll provide Objective-C code snippets corresponding to basic Swift concepts. These examples will cover variables, functions, classes, and more, tailored for someone with Swift experience.
1. Variables and Constants
Swift:
swift
var mutableName = "World"
let constantName = "World"
Objective-C:
objective
NSString *mutableName = @"World";
const NSString *constantName = @"World";
2. Functions
Swift:
swift
func greet(name: String) {
print("Hello, \(name)!")
}
greet(name: "World")
Objective-C:
objective
- (void)greetWithName:(NSString *)name {
NSLog(@"Hello, %@!", name);
}
// Usage
[self greetWithName:@"World"];
3. Classes and Objects
Swift:
swift
class Greeter {
var name: String
init(name: String) {
self.name = name
}
func greet() {
print("Hello, \(name)!")
}
}
let greeter = Greeter(name: "World")
greeter.greet()
Objective-C:
objective
@interface Greeter : NSObject
@property (strong, nonatomic) NSString *name;
- (instancetype)initWithName:(NSString *)name;
- (void)greet;
@end
@implementation Greeter
- (instancetype)initWithName:(NSString *)name {
self = [super init];
if (self) {
_name = name;
}
return self;
}
- (void)greet {
NSLog(@"Hello, %@!", self.name);
}
@end
// Usage
Greeter *greeter = [[Greeter alloc] initWithName:@"World"];
[greeter greet];
4. Control Flow
Swift:
swift
let scores = [75, 43, 103, 87, 12]
for score in scores {
if score > 50 {
print("Pass")
} else {
print("Fail")
}
}
Objective-C:
objective
NSArray *scores = @[@75, @43, @103, @87, @12];
for (NSNumber *score in scores) {
if ([score intValue] > 50) {
NSLog(@"Pass");
} else {
NSLog(@"Fail");
}
}
5. Optionals and Nil
Swift:
swift
var optionalName: String? = "World"
print(optionalName) // Optional("World")
Objective-C:
objective
NSString *optionalName = @"World";
NSLog(@"%@", optionalName); // World
6. Error Handling
Swift:
swift
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
func sendToPrinter(_ jobName: String) throws -> String {
if jobName == "Booklet" {
throw PrinterError.noToner
}
return "Job sent"
}
Objective-C:
objective
typedef NS_ENUM(NSInteger, PrinterError) {
PrinterErrorOutOfPaper,
PrinterErrorNoToner,
PrinterErrorOnFire
};
- (BOOL)sendToPrinter:(NSString *)jobName error:(NSError **)error {
if ([jobName isEqualToString:@"Booklet"]) {
if (error) {
*error = [NSError errorWithDomain:@"PrinterErrorDomain" code:PrinterErrorNoToner userInfo:nil];
}
return NO;
}
return YES;
}
// Usage
NSError *error = nil;
BOOL success = [self sendToPrinter:@"Booklet" error:&error];
if (!success) {
NSLog(@"Failed to send to printer: %@", error);
}
These examples should help you get started with Objective-C if you're familiar with Swift. Remember that while the two languages have different syntax and conventions, the underlying principles of programming remain the same.
________
Let's continue where we left off and provide more examples of Objective-C code for someone transitioning from Swift. We'll focus on more advanced concepts such as collection manipulation, subclassing, protocols, and error handling.
7. Collections (Arrays and Dictionaries)
Swift:
swift
var fruits = ["Apple", "Banana", "Cherry"]
fruits.append("Date")
var carSpecifications = ["make": "Tesla", "model": "Model 3"]
carSpecifications["year"] = "2021"
Objective-C:
objective
// Arrays
NSMutableArray *fruits = [NSMutableArray arrayWithObjects:@"Apple", @"Banana", @"Cherry", nil];
[fruits addObject:@"Date"];
// Dictionaries
NSMutableDictionary *carSpecifications = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"Tesla", @"make", @"Model 3", @"model", nil];
[carSpecifications setObject:@"2021" forKey:@"year"];
8. Subclassing and Initialization
Swift:
swift
class Vehicle {
var numberOfWheels: Int
init(numberOfWheels: Int) {
self.numberOfWheels = numberOfWheels
}
}
class Bicycle: Vehicle {
init() {
super.init(numberOfWheels: 2)
}
}
let bike = Bicycle()
print(bike.numberOfWheels) // 2
Objective-C:
objective
// Vehicle.h
@interface Vehicle : NSObject
@property (assign, nonatomic) NSInteger numberOfWheels;
- (instancetype)initWithNumberOfWheels:(NSInteger)numberOfWheels;
@end
// Vehicle.m
@implementation Vehicle
- (instancetype)initWithNumberOfWheels:(NSInteger)numberOfWheels {
self = [super init];
if (self) {
_numberOfWheels = numberOfWheels;
}
return self;
}
@end
// Bicycle.h
@interface Bicycle : Vehicle
- (instancetype)init;
@end
// Bicycle.m
@implementation Bicycle
- (instancetype)init {
self = [super initWithNumberOfWheels:2];
return self;
}
@end
// Usage
Bicycle *bike = [[Bicycle alloc] init];
NSLog(@"%ld", (long)bike.numberOfWheels); // 2
9. Protocols (Similar to Swift's Protocols)
Swift:
swift
protocol Identifiable {
var id: String { get set }
}
func displayID(thing: Identifiable) {
print("My ID is \(thing.id).")
}
Objective-C:
objective
// Identifiable.h
@protocol Identifiable <NSObject>
@property (strong, nonatomic) NSString *id;
@end
// SomeClass.h
@interface SomeClass : NSObject <Identifiable>
@end
// SomeClass.m
@implementation SomeClass
@synthesize id;
@end
// Usage
SomeClass *someObject = [[SomeClass alloc] init];
someObject.id = @"12345";
NSLog(@"My ID is %@.", someObject.id);
10. Error Handling
Swift:
swift
enum FileError: Error {
case fileDoesNotExist
}
func readFileContents(_ filename: String) throws -> String {
guard let fileContents = try? String(contentsOfFile: filename) else {
throw FileError.fileDoesNotExist
}
return fileContents
}
do {
let contents = try readFileContents("example.txt")
print(contents)
} catch {
print(error)
}
Objective-C:
objective
// FileError.h
typedef NS_ENUM(NSUInteger, FileError) {
FileErrorFileDoesNotExist,
};
// Utility.h
@interface Utility : NSObject
+ (NSString *)readFileContents:(NSString *)filename error:(NSError **)error;
@end
// Utility.m
@implementation Utility
+ (NSString *)readFileContents:(NSString *)filename error:(NSError **)error {
NSString *fileContents = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:error];
if (!fileContents && error) {
*error = [NSError errorWithDomain:@"com.example.error" code:FileErrorFileDoesNotExist userInfo:nil];
}
return fileContents;
}
@end
// Usage
NSError *error = nil;
NSString *contents = [Utility readFileContents:@"example.txt" error:&error];
if (!contents) {
NSLog(@"Error: %@", error);
} else {
NSLog(@"%@", contents);
}
These examples demonstrate how to translate Swift code that performs various operations into Objective-C. While the syntax is different, the core logic behind the code remains similar, allowing for transferable problem-solving skills between the two languages.
________
Let's dive into some specific coding examples that cover the second set of Swift concepts translated into Objective-C.
Collection Types
Swift:
swift
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
Objective-C:
objective
NSArray *names = @[@"Anna", @"Alex", @"Brian", @"Jack"];
for (NSString *name in names) {
NSLog(@"Hello, %@!", name);
}
Error Handling
Swift:
swift
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}
Objective-C:
objective
typedef NS_ENUM(NSInteger, PrinterError) {
PrinterErrorOutOfPaper,
PrinterErrorNoToner,
PrinterErrorOnFire
};
- (NSString *)sendJob:(NSInteger)job toPrinter:(NSString *)printerName error:(NSError **)error {
if ([printerName isEqualToString:@"Never Has Toner"]) {
if (error) {
*error = [NSError errorWithDomain:@"PrinterError" code:PrinterErrorNoToner userInfo:nil];
}
return nil;
}
return @"Job sent";
}
// Usage
NSError *error = nil;
NSString *result = [self sendJob:1024 toPrinter:@"Never Has Toner" error:&error];
if (error) {
NSLog(@"Failed to send job: %@", error.localizedDescription);
} else {
NSLog(@"%@", result);
}
Type Casting
Swift:
swift
let someObjects: [Any] = [2, 2.0, "three"]
for object in someObjects {
switch object {
case let someInt as Int:
print("an integer value of \(someInt)")
case let someDouble as Double where someDouble > 0:
print("a positive double value of \(someDouble)")
case is Double:
print("some other double value that's not positive")
case let someString as String:
print("a string value of \"\(someString)\"")
default:
print("something else")
}
}
Objective-C:
objective
NSArray *someObjects = @[@2, @2.0, @"three"];
for (id object in someObjects) {
if ([object isKindOfClass:[NSNumber class]]) {
// Check if it's an integer or a double
if (strcmp([object objCType], @encode(int)) == 0) {
NSLog(@"an integer value of %d", [object intValue]);
} else if (strcmp([object objCType], @encode(double)) == 0) {
double value = [object doubleValue];
if (value > 0) {
NSLog(@"a positive double value of %f", value);
} else {
NSLog(@"some other double value that's not positive");
}
}
} else if ([object isKindOfClass:[NSString class]]) {
NSLog(@"a string value of \"%@\"", object);
} else {
NSLog(@"something else");
}
}
Protocols
Swift:
swift
protocol FullyNamed {
var fullName: String { get }
}
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John Appleseed")
print(john.fullName)
Objective-C:
objective
@protocol FullyNamed
@property (nonatomic, readonly) NSString *fullName;
@end
@interface Person : NSObject <FullyNamed>
@property (nonatomic, readwrite, copy) NSString *fullName;
@end
@implementation Person
// Synthesize the property for the protocol's requirement
@synthesize fullName = _fullName;
@end
// Usage
Person *john = [Person new];
john.fullName = @"John Appleseed";
NSLog(@"%@", john.fullName);
These examples demonstrate how to perform similar operations in Objective-C that you might be familiar with in Swift. Understanding how to map Swift concepts to Objective-C helps in learning the older language, even as the iOS development community continues to shift towards Swift.
________
Let's continue with the third set of examples for common programming constructs in Objective-C that correspond to those you might be familiar with from Swift.
Enums and Switch Statements
Swift:
swift
enum Direction {
case north
case south
case east
case west
}
let walkingDirection = Direction.north
switch walkingDirection {
case .north:
print("Heading North")
case .south:
print("Heading South")
case .east:
print("Heading East")
case .west:
print("Heading West")
}
Objective-C:
objective
typedef NS_ENUM(NSInteger, Direction) {
DirectionNorth,
DirectionSouth,
DirectionEast,
DirectionWest
};
Direction walkingDirection = DirectionNorth;
switch (walkingDirection) {
case DirectionNorth:
NSLog(@"Heading North");
break;
case DirectionSouth:
NSLog(@"Heading South");
break;
case DirectionEast:
NSLog(@"Heading East");
break;
case DirectionWest:
NSLog(@"Heading West");
break;
default:
break;
}
Closures and Blocks
Swift:
swift
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
var reversedNames = names.sorted(by: { $0 > $1 })
print(reversedNames)
Objective-C:
objective
NSArray *names = @[@"Chris", @"Alex", @"Ewa", @"Barry", @"Daniella"];
NSArray *reversedNames = [names sortedArrayUsingComparator:^NSComparisonResult(NSString *name1, NSString *name2) {
return [name2 compare:name1];
}];
NSLog(@"%@", reversedNames);
Optionals and Unwrapping
Swift:
swift
var optionalName: String? = "John Appleseed"
if let name = optionalName {
print("Hello, \(name)")
} else {
print("No name provided")
}
Objective-C:
objective
NSString *optionalName = @"John Appleseed";
if (optionalName) {
NSLog(@"Hello, %@", optionalName);
} else {
NSLog(@"No name provided");
}
Properties
Swift:
swift
class Person {
var name: String
init(name: String) {
self.name = name
}
}
let john = Person(name: "John Appleseed")
print(john.name)
Objective-C:
objective
@interface Person : NSObject
@property (strong, nonatomic) NSString *name;
- (instancetype)initWithName:(NSString *)name;
@end
@implementation Person
- (instancetype)initWithName:(NSString *)name {
self = [super init];
if (self) {
_name = name;
}
return self;
}
@end
// Usage
Person *john = [[Person alloc] initWithName:@"John Appleseed"];
NSLog(@"%@", john.name);
Asynchronous Operations
Swift:
swift
func fetchData(completion: @escaping (Data?) -> Void) {
// Assuming we're using URLSession to fetch data.
let url = URL(string: "https://example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else {
completion(nil)
return
}
completion(data)
}
task.resume()
}
fetchData { data in
if let data = data {
print("Data received: \(data)")
}
}
Objective-C:
objective
- (void)fetchDataWithCompletion:(void (^)(NSData *data))completion {
NSURL *url = [NSURL URLWithString:@"https://example.com/data"];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (data) {
completion(data);
} else {
completion(nil);
}
}];
[task resume];
}
// Usage
[self fetchDataWithCompletion:^(NSData *data) {
if (data) {
NSLog(@"Data received: %@", data);
}
}];
These Objective-C examples are designed to parallel the Swift examples from your theoretical P-Set, giving you a practical understanding of how to perform similar tasks in both languages.
________
Let's explore the fourth P-Set with additional examples that take more advanced Swift features and show their Objective-C equivalents.
Generics
Swift:
swift
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
// someInt is now 107, and anotherInt is now 3
Objective-C: Objective-C does not support generics in the same way Swift does. However, you can use id for a similar, though not type-safe, effect.
objective
- (void)swapTwoValues:(id *)a with:(id *)b {
id temporaryA = *a;
*a = *b;
*b = temporaryA;
}
// Usage
id someInt = @3;
id anotherInt = @107;
[self swapTwoValues:&someInt with:&anotherInt];
// someInt is now 107, and anotherInt is now 3
Objective-C introduced lightweight generics with __kindof and type annotations for collections in recent versions, but they do not provide the same level of generic programming as Swift.
Extensions
Swift:
swift
extension Int {
func squared() -> Int {
return self * self
}
}
let number = 7
print(number.squared())
// Prints 49
Objective-C: In Objective-C, you can use categories to achieve similar functionality to Swift extensions.
objective
@interface NSNumber (Squared)
- (NSNumber *)squared;
@end
@implementation NSNumber (Squared)
- (NSNumber *)squared {
return @(self.intValue * self.intValue);
}
// Usage
NSNumber *number = @7;
NSLog(@"%@", [number squared]);
// Prints 49
Asynchronous Calls with Completion Handlers
Swift:
swift
func fetchDocument(completion: @escaping (String) -> Void) {
// Perform asynchronous operation
DispatchQueue.global().async {
// Simulate fetching document
let document = "Document data"
DispatchQueue.main.async {
completion(document)
}
}
}
fetchDocument { document in
print(document)
}
Objective-C:
objective
- (void)fetchDocumentWithCompletion:(void (^)(NSString *document))completion {
// Perform asynchronous operation
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Simulate fetching document
NSString *document = @"Document data";
dispatch_async(dispatch_get_main_queue(), ^{
completion(document);
});
});
}
// Usage
[self fetchDocumentWithCompletion:^(NSString *document) {
NSLog(@"%@", document);
}];
Key-Value Observing
Swift:
swift
class MyObject: NSObject {
@objc dynamic var value = 0
}
let myObject = MyObject()
let observation = myObject.observe(\.value, options: [.old, .new]) { object, change in
print("Value changed from \(change.oldValue!) to \(change.newValue!)")
}
myObject.value = 1
// Prints "Value changed from 0 to 1"
Objective-C:
objective
@interface MyObject : NSObject
@property (nonatomic) NSInteger value;
@end
@implementation MyObject
// Synthesize automatically generated by the compiler
@end
MyObject *myObject = [[MyObject alloc] init];
[myObject addObserver:self forKeyPath:@"value" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
[myObject setValue:@1 forKey:@"value"];
// And then implement the observation method:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"value"]) {
NSLog(@"Value changed from %@ to %@", [change objectForKey:NSKeyValueChangeOldKey], [change objectForKey:NSKeyValueChangeNewKey]);
}
}
// Don't forget to remove observer
[myObject removeObserver:self forKeyPath:@"value"];
These examples illustrate how to approach Swift's advanced features in Objective-C, even though some features do not have a direct one-to-one equivalent due to language differences. The essence of the functionality can often still be achieved, albeit with slightly different syntax or constructs.
________
Let’s translate some more complex Swift constructs into Objective-C for our fifth P-Set of examples.
Delegates
Swift:
swift
protocol SomeDelegate {
func didReceiveData(_ data: String)
}
class SomeClass {
var delegate: SomeDelegate?
func fetchData() {
// Data was fetched
delegate?.didReceiveData("Data")
}
}
class DelegateClass: SomeDelegate {
func didReceiveData(_ data: String) {
print("Received data: \(data)")
}
}
let someInstance = SomeClass()
let delegateInstance = DelegateClass()
someInstance.delegate = delegateInstance
someInstance.fetchData()
// Prints: Received data: Data
Objective-C:
objective
@protocol SomeDelegate <NSObject>
- (void)didReceiveData:(NSString *)data;
@end
@interface SomeClass : NSObject
@property (weak, nonatomic) id<SomeDelegate> delegate;
- (void)fetchData;
@end
@implementation SomeClass
- (void)fetchData {
// Data was fetched
[self.delegate didReceiveData:@"Data"];
}
@end
@interface DelegateClass : NSObject <SomeDelegate>
@end
@implementation DelegateClass
- (void)didReceiveData:(NSString *)data {
NSLog(@"Received data: %@", data);
}
@end
// Usage
SomeClass *someInstance = [[SomeClass alloc] init];
DelegateClass *delegateInstance = [[DelegateClass alloc] init];
someInstance.delegate = delegateInstance;
[someInstance fetchData];
// Prints: Received data: Data
Grand Central Dispatch (GCD) for Concurrency
Swift:
swift
DispatchQueue.global(qos: .userInitiated).async {
let largeImage = downloadImageFromServer()
DispatchQueue.main.async {
imageView.image = largeImage
}
}
Objective-C:
objective
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
UIImage *largeImage = [self downloadImageFromServer];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = largeImage;
});
});
Notification Center
Swift:
swift
NotificationCenter.default.addObserver(
self,
selector: #selector(didReceiveNotification(_:)),
name: NSNotification.Name("MyNotification"),
object: nil
)
@objc func didReceiveNotification(_ notification: Notification) {
print("Notification received!")
}
Objective-C:
objective
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveNotification:)
name:@"MyNotification"
object:nil];
- (void)didReceiveNotification:(NSNotification *)notification {
NSLog(@"Notification received!");
}
// Don't forget to remove observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
Optionals and Handling Nil
Swift:
swift
var optionalString: String? = "This is optional"
print(optionalString ?? "Default value")
Objective-C:
objective
NSString *optionalString = @"This is optional";
NSLog(@"%@", optionalString ?: @"Default value");
Auto Layout Constraints Programmatically
Swift:
swift
let redView = UIView()
redView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
redView.topAnchor.constraint(equalTo: view.topAnchor),
redView.leftAnchor.constraint(equalTo: view.leftAnchor),
redView.widthAnchor.constraint(equalToConstant: 100),
redView.heightAnchor.constraint(equalToConstant: 100)
])
Objective-C:
objective
UIView *redView = [[UIView alloc] init];
redView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[redView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[redView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],
[redView.widthAnchor constraintEqualToConstant:100],
[redView.heightAnchor constraintEqualToConstant:100]
]];
These Objective-C examples showcase how you might adapt Swift code to perform similar operations. These snippets can be particularly useful for iOS developers who are familiar with Swift but need to maintain or update older codebases in Objective-C.
________
For our sixth P-Set, we'll continue translating Swift functionality into Objective-C examples. This set will cover closures (blocks in Objective-C), properties with custom getters and setters, subscripting, and working with dates.
Closures (Blocks in Objective-C)
Swift:
swift
let completionBlock = { (finished: Bool) in
print("Completed with status: \(finished)")
}
completionBlock(true)
Objective-C:
objective
void (^completionBlock)(BOOL) = ^(BOOL finished){
NSLog(@"Completed with status: %d", finished);
};
completionBlock(YES);
Properties with Custom Getters and Setters
Swift:
swift
class Temperature {
private var celsius: Double
var fahrenheit: Double {
get {
return celsius * 1.8 + 32
}
set {
celsius = (newValue - 32) / 1.8
}
}
init(celsius: Double) {
self.celsius = celsius
}
}
let temp = Temperature(celsius: 0)
print(temp.fahrenheit) // Prints 32
temp.fahrenheit = 212
print(temp.celsius) // Prints 100
Objective-C:
objective
@interface Temperature : NSObject
@property (nonatomic, assign) double celsius;
@property (nonatomic, assign) double fahrenheit;
@end
@implementation Temperature
- (double)fahrenheit {
return self.celsius * 1.8 + 32;
}
- (void)setFahrenheit:(double)newFahrenheit {
self.celsius = (newFahrenheit - 32) / 1.8;
}
- (instancetype)initWithCelsius:(double)celsius {
if ((self = [super init])) {
_celsius = celsius;
}
return self;
}
@end
// Usage
Temperature *temp = [[Temperature alloc] initWithCelsius:0];
NSLog(@"%f", temp.fahrenheit); // Prints 32
[temp setFahrenheit:212];
NSLog(@"%f", temp.celsius); // Prints 100
Subscripting
Swift:
swift
class DaysOfWeek {
private var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
subscript(index: Int) -> String {
get {
return days[index]
}
set(newValue) {
self.days[index] = newValue
}
}
}
let myDays = DaysOfWeek()
print(myDays[0]) // Prints "Sunday"
myDays[0] = "Funday"
print(myDays[0]) // Prints "Funday"
Objective-C: Objective-C does not directly support subscripting for custom classes without using collections, but you can implement accessor methods to provide similar functionality.
objective
@interface DaysOfWeek : NSObject
- (NSString *)objectAtIndexedSubscript:(NSInteger)idx;
- (void)setObject:(NSString *)obj atIndexedSubscript:(NSInteger)idx;
@end
@implementation DaysOfWeek {
NSMutableArray *_days;
}
- (instancetype)init {
if ((self = [super init])) {
_days = [@[@"Sunday", @"Monday", @"Tuesday", @"Wednesday", @"Thursday", @"Friday", @"Saturday"] mutableCopy];
}
return self;
}
- (NSString *)objectAtIndexedSubscript:(NSInteger)idx {
return [_days objectAtIndex:idx];
}
- (void)setObject:(NSString *)obj atIndexedSubscript:(NSInteger)idx {
[_days replaceObjectAtIndex:idx withObject:obj];
}
@end
// Usage
DaysOfWeek *myDays = [[DaysOfWeek alloc] init];
NSLog(@"%@", myDays[0]); // Prints "Sunday"
myDays[0] = @"Funday";
NSLog(@"%@", myDays[0]); // Prints "Funday"
Working with Dates
Swift:
swift
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd"
let date = dateFormatter.date(from: "2024/01/24")
Objective-C:
objective
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy/MM/dd"];
NSDate *date = [dateFormatter dateFromString:@"2024/01/24"];
These examples cover a range of common coding scenarios and demonstrate the translation from Swift's syntax and conventions into Objective-C's, accommodating the differences between the two languages. Objective-C's more verbose syntax and use of brackets can seem cumbersome at first to a Swift developer, but with practice, the patterns become more familiar.
________
To help students consolidate their understanding of Objective-C and facilitate long-term memory retention of its syntax and concepts, it's important to pose questions that encourage deep thinking and application of knowledge. Here are major questions that can help reinforce learning and ensure students are not only familiar with Objective-C commands but also understand how and when to use them effectively:
Basics and Syntax
How do you declare a variable in Objective-C, and how does it differ from variable declaration in Swift?
Explain the significance of pointers in Objective-C. How do you declare a pointer to an integer?
Functions and Methods
What is the syntax for declaring a method in Objective-C? How do you differentiate between instance and class methods?
Provide an example of a method in Objective-C that takes multiple parameters. How are parameters passed to Objective-C methods?
Object-Oriented Concepts
How do you define a class in Objective-C? Include examples of .h (header) and .m (implementation) files.
Describe inheritance in Objective-C. How do you create a subclass, and how is it different from Swift?
What are properties in Objective-C? Explain how to declare a read-only property.
Memory Management
Explain the concept of Automatic Reference Counting (ARC) in Objective-C. How does it manage memory?
What are strong and weak references in Objective-C? Provide examples of when to use each.
Collection Types
How do you use arrays and dictionaries in Objective-C? Show examples of creating and accessing elements in mutable and immutable collections.
Control Flow
Compare and contrast the syntax for if statements and for loops in Objective-C and Swift. Provide examples.
How do you use switch statements in Objective-C? Do they work with objects?
Advanced Topics
What are blocks in Objective-C, and how are they used? Provide an example of a block that takes parameters and returns a value.
Describe how to implement protocols and delegates in Objective-C. Provide an example scenario where a delegate might be used.
How do you handle errors in Objective-C? Compare it with Swift's error handling.
Practical Applications and Best Practices
When would you choose to use Objective-C over Swift in a project? Consider factors like legacy code, third-party libraries, and specific frameworks.
Discuss key differences in UI development between Objective-C and Swift. How do you define a UI programmatically in Objective-C?
How do you perform network requests in Objective-C? Provide an example using NSURLSession.
What are some best practices for writing clean, maintainable Objective-C code? Discuss naming conventions, code organization, and comment usage.
Debugging and Tools
Describe the process of debugging an Objective-C application in Xcode. How do you set breakpoints, and what tools do you use to inspect variables?
Encouraging students to actively engage with these questions, either through written responses, discussions, or coding exercises, will help deepen their understanding of Objective-C. It's also beneficial to encourage them to build small projects or components within larger apps using Objective-C to apply what they've learned in a practical context.