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)

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:

Here are some additional tips:

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

Object-Oriented Programming

Advanced Topics

Collections and Control Structures

Modern Objective-C Features

Development Environment

Practice and Application

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

Functions and Methods

Object-Oriented Concepts

Memory Management

Collection Types

Control Flow

Advanced Topics

Practical Applications and Best Practices

Debugging and Tools

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.