Author: Pooja Kotwani

  • Typedef in Objective-C

    Typedef in detail

    typedef allows us to assign a new name to an existing data type. For instance, typedef unsigned char CAT; makes CAT an alias for unsigned char, so from then on, you can use CAT as a shorthand for unsigned char, like in the declaration CAT num1, num2;. In other words, typedef is a keyword used to create an alias for predefined or user-defined data types, making code more readable. A typedef essentially helps simplify long data type names by creating an alias.

    The typedef specifier is used in a declaration to indicate that it is creating a new type, not declaring a variable or function. Typically, typedef appears at the start of the declaration but can also appear after the type identifier or between two type identifiers. A typedef can define multiple identifiers on the same line, such as for integer and pointer types, arrays, functions, or class types. After using typedef, the created identifier is synonymous with the type it represents. Importantly, typedef cannot be combined with other specifiers apart from typedef.

    Syntax:

    typedef unsigned long long BUTTON;

    Example 1:

    // Objective-C program to demonstrate the use of typedef
    #import <Foundation/Foundation.h>
    
    // Defining new names for existing data types using typedef
    typedef int MOUSE;
    typedef unsigned long long CAT;
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        // Creating variables using the new typedef names
        MOUSE x = 10000;
        CAT y = 121234;
    
        // Displaying the values
        NSLog(@"Value of x is %i", x);
        NSLog(@"Value of y is %llu", y);
    
        [pool drain];
        return 0;
    }

    Output:

    Value of x is 10000
    Value of y is 121234

    Example 2:

    // Objective-C program to demonstrate the use of typedef with struct
    #import <Foundation/Foundation.h>
    
    // Creating a struct and using typedef to define a new type
    typedef struct Author {
    
        // Struct variables
        NSString *Title;
        NSString *Publisher;
        int Book_Number;
    } Author;
    
    // Driver code
    int main() {
        // Creating an object of the Author struct
        Author author;
    
        // Assigning values to the struct variables
        author.Title = @"Learn Objective-C for Beginners";
        author.Publisher = @"TechBooks";
        author.Book_Number = 123;
    
        // Displaying the values
        NSLog(@"Book title: %@", author.Title);
        NSLog(@"Book publisher: %@", author.Publisher);
        NSLog(@"Book ID: %d", author.Book_Number);
    
        return 0;
    }

    Output:

    Book title: Learn Objective-C for Beginners
    Book publisher: TechBooks
    Book ID: 123

    Difference Between typedef and #define

    Featuretypedef#define
    TypeCompiler tokenPreprocessor token
    PurposeDefines new typesDefines macros
    UsageCreates an alias for typesCreates constants for numbers, strings, and expressions
    ScopeLimited to types onlyCan define constants for values and expressions too
    Exampletypedef int MY_INT;#define PI 3.14
  • Preprocessors in Objective-C

    Preprocessors and Their Types

    Preprocessors are essential tools that assist in tasks like reusability and conditional compilation. This article explores the role of preprocessors in Objective-C.

    What are Objective-C Preprocessors?

    Preprocessors in Objective-C are special directives that help in tasks such as defining macros or including header files necessary for compiling a program. The compiler processes these directives before the source code is compiled, ensuring that all essential files or functions are properly handled.

    #define LENGTH 20
    Types of Preprocessors in Objective-C

    Here are the various types of preprocessors used in Objective-C:

    A) Preprocessor Directives:

    These directives provide instructions to the compiler before compilation. The commonly used preprocessor directives are:

    1. #define: Defines a macro and associates it with a specified value. Every time the macro appears in the code, it gets replaced with the assigned value.

    2. #include: Includes a header file from another file into the current file.

    3. #undef: Removes a previously defined macro.

    4. #ifdef: Conditionally includes or excludes code depending on whether a specific macro is defined.

    5. #ifndef: The reverse of #ifdef, this conditionally includes or excludes code based on whether a macro is not defined.

    6. #import: Similar to #include, but ensures that the header file is included only once.

    7. #if: Controls which code blocks are compiled based on conditions.

    8. #else: Specifies an alternative code path when the #if condition is not met.

    9. #elif: Combines #else and #if into a single directive to simplify code.

    10. #endif: Marks the end of a conditional block.

    11. #error: Outputs an error message to the standard error output.

    12. #pragma: Issues specific commands to the compiler for specialized instructions.

    B)  Preprocessor Operators:

    Preprocessor operators enhance the functionality of macros. The following are key operators in Objective-C:

    1. Macro Continuation Operator (\): Allows a macro to span multiple lines when it exceeds a single line.
    Example:

    // File - MessageMacro.m
    
    #import <Foundation/Foundation.h>
    
    // Macro Continuation Operator
    #define message_for(a, b) \
    NSLog(@#a " and " #b ": Welcome to Objective-C!\n")
    
    int main(void)
    {
      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      message_for(Rahul , Sohan);
      [pool drain];
      return 0;
    }

    Output:

    // Declaring and initializing structure members
    struct student st1;
    
    st1.name = @"Student 1";
    st1.trade = @"Computer Science";
    st1.regNo = 123;
    st1.age = 21;

    2. Stringize Operator (#): Converts a macro parameter into a string constant.
    Example:

    // File - StringizeMacro.m
    
    #import <Foundation/Foundation.h>
    
    #define message_for(a, b) \
    NSLog(@#a " and " #b ": are planets!\n")
    
    int main(void)
    {
      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      message_for(Sun , Saturn);
      [pool drain];
      return 0;
    }

    Output:

    Sun and Saturn: are planets!

    3. Token Pasting Operator (##): Concatenates two or more arguments into a single argument.
    Example:

    #import <Foundation/Foundation.h>
    
    #define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
    
    int main(void) {
      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      int token34 = 40;
      tokenpaster(34);
      [pool drain];
      return 0;
    }

    Output:

    token34 = 40

    4. Defined Operator (defined): Checks whether a constant expression has been defined using #define.
    Example:

    #include <Foundation/Foundation.h>
    
    // Define a macro for debug mode
    #if !defined DEBUG
       #define DEBUG "Debugging is On"
    #endif
    
    int main() {
      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      NSLog(@"Here is the message: %s\n", DEBUG);
      [pool drain];
      return 0;
    }

    Output:

    Here is the message: Debugging is On
  • Structures in Objective-C

    Objective-C is an object-oriented programming language that extends the C language with object-oriented capabilities. It follows a bottom-up approach and supports both procedural and object-oriented paradigms. One of the data structures supported by Objective-C is the structure. This article covers how to define and use structures in Objective-C.

    Structures

    structure is a user-defined data type in Objective-C that allows grouping different data types together. A structure enables you to combine multiple types of data into a single unit. For instance, if we want to store a student’s information, such as their name (string), trade (string), registration number (integer), and age (integer), we can use a structure.

    Defining a Structure

    A structure in Objective-C is created using the struct keyword, followed by the structure name. Within the structure, we can define multiple data members.

    Syntax:

    struct structure_name {
        data_type1 member1;
        data_type2 member2;
    };

    It’s possible to declare one or more variables of the structure type at the end of its definition (this step is optional).

    Example:

    We define a structure called student that holds two strings (for name and trade) and two integers (for registration number and age):

    // Creating a structure to store student data
    struct student {
      NSString *name;
      NSString *trade;
      int regNo;
      int age;
    };
    Initializing Structure Members

    Unlike some other languages, structure members cannot be initialized during their declaration. Initialization occurs after creating a structure variable, using dot notation (.).

    Example:

    // Declaring and initializing structure members
    struct student st1;
    
    st1.name = @"Student 1";
    st1.trade = @"Computer Science";
    st1.regNo = 123;
    st1.age = 21;
    Accessing Structure Members

    To access a structure’s data members, use dot notation (.). The structure variable’s name is followed by the dot and the member name.

    Syntax:

    struct structure_name variable_name;
    variable_name.member1;
    variable_name.member2;

    Example:

    // Objective-C program using structure to store student data
    #import <Foundation/Foundation.h>
    
    // Defining structure
    struct student {
      NSString *name;
      NSString *trade;
      int regNo;
      int age;
    };
    
    int main() {
      struct student st1, st2;
    
      // Initializing st1
      st1.name = @"Student1";
      st1.trade = @"Computer Science";
      st1.regNo = 123;
      st1.age = 21;
    
      // Initializing st2
      st2.name = @"Student2";
      st2.trade = @"Electronics";
      st2.regNo = 987;
      st2.age = 20;
    
      // Printing st1 data
      NSLog(@"Student 1 Name: %@\n", st1.name);
      NSLog(@"Student 1 Trade: %@\n", st1.trade);
      NSLog(@"Student 1 RegNo: %d\n", st1.regNo);
      NSLog(@"Student 1 Age: %d\n", st1.age);
    
      // Printing st2 data
      NSLog(@"Student 2 Name: %@\n", st2.name);
      NSLog(@"Student 2 Trade: %@\n", st2.trade);
      NSLog(@"Student 2 RegNo: %d\n", st2.regNo);
      NSLog(@"Student 2 Age: %d\n", st2.age);
    
      return 0;
    }

    Output:

    Student 1 Name: Student1
    Student 1 Trade: Computer Science
    Student 1 RegNo: 123
    Student 1 Age: 21
    
    Student 2 Name: Student2
    Student 2 Trade: Electronics
    Student 2 RegNo: 987
    Student 2 Age: 20

    Pointers to a Structure

    Like primitive data types, you can have pointers to structures. The pointer is defined using the * symbol, similar to other types of pointers.

    struct student *student_ptr;

    You can store the address of a structure variable in the pointer by using the address-of operator (&):

    student_ptr = &st1;

    To access members of a structure via a pointer, use the arrow operator (->):

    student_ptr->name

    Example: Using Pointers to Access Structure Members

    // Objective-C program using pointers to access structure members
    #import <Foundation/Foundation.h>
    
    // Defining structure
    struct student {
      NSString *name;
      NSString *trade;
      int regNo;
      int age;
    };
    
    int main() {
      struct student st1;
      struct student *student_ptr;
    
      student_ptr = &st1;
    
      // Initializing st1
      st1.name = @"Student1";
      st1.trade = @"Computer Science";
      st1.regNo = 123;
      st1.age = 21;
    
      // Printing st1 info using direct access
      NSLog(@"Printing st1 info directly\n");
      NSLog(@"Name: %@\n", st1.name);
      NSLog(@"Trade: %@\n", st1.trade);
      NSLog(@"RegNo: %d\n", st1.regNo);
      NSLog(@"Age: %d\n", st1.age);
    
      // Printing st1 info using pointer
      NSLog(@"\nPrinting st1 info using pointer\n");
      NSLog(@"Name: %@\n", student_ptr->name);
      NSLog(@"Trade: %@\n", student_ptr->trade);
      NSLog(@"RegNo: %d\n", student_ptr->regNo);
      NSLog(@"Age: %d\n", student_ptr->age);
    
      return 0;
    }

    Output:

    Printing st1 info directly
    Name: Student1
    Trade: Computer Science
    RegNo: 123
    Age: 21
    
    Printing st1 info using pointer
    Name: Student1
    Trade: Computer Science
    RegNo: 123
    Age: 21
  • String in Objective-C

    Strings and Their Type

    Strings are a fundamental concept in programming, used to represent sequences of text. In Objective-C, strings are objects that store sequences of characters. These characters can include letters, digits, symbols, or any other textual data. Objective-C provides various classes and methods for creating and manipulating strings, allowing for different ways of working with text.

    Types of Strings

    1. NSString: This is an immutable object that represents a sequence of characters. Once created, the string cannot be modified.
    2. NSMutableString: This is a mutable object that allows changes after creation. You can add, remove, or modify characters.
    3. CFString: This is a Core Foundation object used to represent sequences of Unicode characters.

    Built-in Methods for Strings

    Objective-C offers several classes and methods for creating and manipulating strings. Here are some commonly used ones:

    MethodPurpose
    NSStringUsed to create an immutable string.
    NSMutableStringUsed to create a mutable string that can be changed.
    lengthReturns the length of the string.
    stringWithFormatFormats a string with specified values.
    substringWithRangeExtracts a substring from the string based on a specified range.
    isEqualToStringCompares two strings for equality.
    stringByAppendingFormatAppends a formatted string to the existing string.

    Example 1: Creating a String with NSString

    In this example, we create a string using the NSString class.

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        // Define a string
        NSString *greeting = @"Hello, Objective-C!";
    
        // Print the string
        NSLog(@"%@", greeting);
    
        return 0;
    }

    Output:

    Hello, Objective-C!

    Example 2: Formatting a String with Values

    Here, we format a string by inserting a variable value into the string using stringWithFormat.

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        // Create an integer variable
        int appleCount = 12;
    
        // Format a string with a value
        NSString *formattedString = [NSString stringWithFormat:@"I have %d apples.", appleCount];
    
        // Print the formatted string
        NSLog(@"%@", formattedString);
    
        return 0;
    }

    Output:

    I have 12 apples.
  • Pointers in Objective-C

    In Objective-C, pointers are variables that store the memory address of another variable. A pointer variable must be declared before use. The size of a pointer depends on the system architecture. Pointers can be of various data types like charintfloatdouble, or other valid types. They are essential for dynamic memory allocation, as memory cannot be allocated dynamically without them.

    Syntax:

    type *var-name;

    Here, type represents the data type of the pointer, and it must be valid. var-name is the name of the variable, and an asterisk (*) is used to declare the pointer.

    Example:

    int *ptr;
    float *number;
    char *mychar;
    How to Use Pointers?

    Step 1: To use a pointer, start by declaring it with a valid name and data type.

    Syntax:

    type *var-name;

    Example:

    int *myPtr;

    Step 2: Assign the address of another variable to the pointer using the & (ampersand) operator, which retrieves the variable’s memory address. For instance, &x gives the address of x.

    Syntax:

    pointer_variable = &var_name;

    Example:

    myPtr = &x1;

    Step 3: To retrieve the value stored at the address, use the * (asterisk) operator.

    Syntax:

    *var_name;

    Example:

    NSLog(@"Pointer Value is %d", *myPtr);

    Example:

    #import <Foundation/Foundation.h>
    
    int main() {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int a = 50;
        int *ptr;
    
        ptr = &a;
    
        NSLog(@"Address of variable a = %p", &a);
        NSLog(@"Address stored in the pointer ptr = %p", ptr);
        NSLog(@"Value of *ptr = %d", *ptr);
    
        [pool drain];
        return 0;
    }

    Output:

    Address of variable a = 0x16fdff10
    Address stored in the pointer ptr = 0x16fdff10
    Value of *ptr = 50

    NULL Pointers

    Null pointers have a value of 0 or NULL. Such pointers are used when no address is assigned at the time of declaration.

    Syntax:

    int *ptr = NULL;

    Example:

    #import <Foundation/Foundation.h>
    
    int main() {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int *myptr = NULL;
    
        NSLog(@"The value of pointer = %p", myptr);
    
        [pool drain];
        return 0;
    }

    Output:

    The value of pointer = 0
    Advantages of Pointers

    1. Enable dynamic memory allocation and deallocation.
    2. Useful for accessing and manipulating memory locations.
    3. Essential for working with data structures like arrays, linked lists, and trees.

    Disadvantages of Pointers

    1. Can be complex to understand.
    2. May cause memory leaks if not handled properly.
    3. Assigning incorrect values can lead to memory corruption.

    Pointers in Detail

    Pointers play a significant role in Objective-C programming and, while their concepts are numerous, they are relatively straightforward to understand. Below are some key pointer concepts that every Objective-C programmer should be familiar with:

    1. Pointer Arithmetic
    2. Array of Pointers
    3. Pointer to Pointer
    4. Passing Pointers to Functions 
    5. Returning Pointers from Functions

    1. Pointer Arithmetic

    Pointers in Objective-C store the memory address of variables. This allows for arithmetic operations on pointers using operators like ++--+, and -. Consider a pointer to an integer, which is located at address 1000. If the integer is 32-bits, performing the following pointer arithmetic operations will result in the pointer advancing by the size of the data type it points to (in this case, 4 bytes for an integer). Let’s explore different pointer arithmetic operations:

    i. Increment of a Pointer: When a pointer is incremented, it moves by the size of the data type it is pointing to. For instance, if an integer pointer starts at address 2000, after incrementing by 4 (size of an integer), the new address it points to will be 2004.

    Example:

    #import <Foundation/Foundation.h>
    
    int main() {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int arr[5] = {10, 20, 30, 40, 50};
        int *ptr = arr;
    
        for (int i = 0; i < 5; i++) {
            NSLog(@"Pointer Arithmetic = %d", *ptr++);
        }
    
        [pool drain];
        return 0;
    }

    Output:

    Pointer Arithmetic = 10
    Pointer Arithmetic = 20
    Pointer Arithmetic = 30
    Pointer Arithmetic = 40
    Pointer Arithmetic = 50

    ii. Decrement of a Pointer: When a pointer is decremented, it moves backwards by the size of the data type it is pointing to. For example, if an integer pointer is at address 2000, after decrementing by 4, the pointer will point to address 1996.

    Example:

    #import <Foundation/Foundation.h>
    
    const int MAX = 5;
    
    int main() {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int arr[] = {10, 20, 30, 40, 50};
        int *ptr = &arr[MAX - 1];
    
        for (int i = MAX; i > 0; i--) {
            NSLog(@"Pointer Arithmetic = %d", *ptr--);
        }
    
        [pool drain];
        return 0;
    }

    Output:

    Pointer Arithmetic = 50
    Pointer Arithmetic = 40
    Pointer Arithmetic = 30
    Pointer Arithmetic = 20
    Pointer Arithmetic = 10

    iii. Addition of an Integer to a Pointer: When an integer is added to a pointer, the pointer’s address increases by the product of the integer and the size of the data type it is pointing to. For example, adding 2 to a pointer will result in the pointer moving forward by 2 times the size of the data type it points to.

    #import <Foundation/Foundation.h>
    
    int main() {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int a = 10, *ptr = &a;
        NSLog(@"Address of ptr: %p", ptr);
    
        ptr = ptr + 2;
        NSLog(@"Address of ptr after addition: %p", ptr);
    
        [pool drain];
        return 0;
    }

    Output:

    Address of ptr: 0x7ffee2b93c7c
    Address of ptr after addition: 0x7ffee2b93c84

    iv. Subtraction of an Integer from a Pointer: When an integer is subtracted from a pointer, the pointer’s address decreases by the product of the integer and the size of the data type it is pointing to.

    Example:

    #import <Foundation/Foundation.h>
    
    int main() {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int a = 10, *ptr = &a;
        NSLog(@"Address of ptr: %p", ptr);
    
        ptr = ptr - 2;
        NSLog(@"Address of ptr after subtraction: %p", ptr);
    
        [pool drain];
        return 0;
    }

    Output:

    Address of ptr: 0x7ffee2b93c7c
    Address of ptr after subtraction: 0x7ffee2b93c74

    Using Pointers to Traverse an Array

    Pointers can also be used to access and traverse arrays, where the array’s name acts as a pointer to its first element. For instance, an array arr can be assigned to a pointer, and we can iterate over the array elements using pointer arithmetic.

    Example:

    #import <Foundation/Foundation.h>
    
    int main() {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int arr[3] = {5, 8, 9};
        int *ptr = arr;
    
        for (int i = 0; i < 3; i++) {
            NSLog(@"Value of ptr[%d]: %d", i, *(ptr + i));
        }
    
        [pool drain];
        return 0;
    }

    Output:

    Value of ptr[0]: 5
    Value of ptr[1]: 8
    Value of ptr[2]: 9
    2. Array of Pointers

    In Objective-C, pointers to arrays are used to store multiple values of the same data type in contiguous memory locations. These pointers allow for dynamic memory management and flexible array manipulation, such as passing arrays to functions or returning them from functions. Additionally, pointers to arrays enable you to allocate memory for arrays during runtime, providing more control over memory usage.

    Arrays in Objective-C can be categorized into different types. Understanding how to work with them using pointers is crucial for writing effective code. The following are common array types and examples:

    Types of Arrays in Objective-C

    i. Static Arrays: A static array is defined with a fixed size, and its size cannot be changed during runtime.

    Example:

    int staticArray[5] = {1, 2, 3, 4, 5};

    ii. Dynamic Arrays: A dynamic array’s size can be changed at runtime by allocating memory with the malloc function.

    Example:

    int *dynamicArray = (int *)malloc(5 * sizeof(int));

    iii. Two-Dimensional Arrays: These arrays are essentially arrays of arrays, similar to a matrix or table.

    Example:

    int twoDimensionalArray[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

    iv.  Character Arrays: A character array stores strings in Objective-C.

    Example:

    char name[5] = "John";

    v. NSArray: NSArray is an Objective-C class that provides an array-based data structure. It can be initialized with various methods, such as arrayWithObjects: and arrayWithContentsOfFile:.

    Example:

    NSArray *fruits = [NSArray arrayWithObjects:@"Apple", @"Banana", @"Cherry", nil];

    vi.  NSMutableArray: NSMutableArray is a subclass of NSArray that allows modification of the array (adding, removing, or replacing elements).

    Example:

    NSMutableArray *colors = [NSMutableArray arrayWithObjects:@"Red", @"Green", @"Blue", nil];
    [colors addObject:@"Yellow"];
    [colors removeObjectAtIndex:2];

    Example: Printing Elements of an NSArray

    This example defines a pointer to an array of int values and prints the elements of the array.

    #import <Foundation/Foundation.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, const char * argv[]) {
       @autoreleasepool {
           // Create an NSArray with integer values
           NSArray *array = @[@1, @2, @3, @4, @5];
    
           // Print the elements of the array
           for (int i = 0; i < [array count]; i++) {
               NSLog(@"%d", [array[i] intValue]);
           }
       }
       return EXIT_SUCCESS;
    }

    Output:

    1
    2
    3
    4
    5

    Example 2: Summing Elements of an NSArray

    This example defines a function that takes a pointer to an array of integers and calculates the sum of the elements.

    #import <Foundation/Foundation.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
       @autoreleasepool {
           // Create an NSArray with integer values
           NSArray *array = @[@1, @2, @3, @4, @5];
    
           // Initialize sum to 0
           int sum = 0;
    
           // Loop through the elements and calculate the sum
           for (int i = 0; i < [array count]; i++) {
               sum += [array[i] intValue];
           }
           NSLog(@"The sum of the elements is %d", sum);
       }
       return EXIT_SUCCESS;
    }

    Output:

    The sum of the elements is 15
    3. Pointer to Pointer

    Pointers in Objective-C are an essential concept for manipulating data directly in memory. A pointer to a pointer, also referred to as a double pointer, is a special type of pointer that stores the address of another pointer. This concept is often used when you need to pass a pointer to a function or to manage dynamically allocated memory.

    There are three main types of pointers in Objective-C:

    i. Regular Pointer: A pointer that holds the address of a variable.

    ii. Pointer to Constant: A pointer that holds the address of a constant value.

    iii. Constant Pointer: A pointer that holds a constant address, which cannot be changed.

    Pointer to Pointer (Double Pointer)

    A pointer to a pointer, or double pointer, stores the address of another pointer. It is declared by using two asterisks (**) in the declaration. The first asterisk represents the type of data the pointer is pointing to, while the second asterisk indicates that it is a pointer to another pointer.

    Syntax:

    data_type **pointer_name;

    For example, a double pointer for integers would be declared as:

    int **p;

    A double pointer allows access to the value stored at the address of the pointer it holds. This involves using &*, and ** operators. The & operator is used to get the address of a variable, the * operator is used to access the value stored at the address held by the pointer, and ** is used to access the value stored at the address held by the pointer to a pointer.

    Example 1: Swapping Two Pointers Using Pointer to Pointer

    This example demonstrates how to use a pointer to pointer to swap the values of two variables by passing pointers to a function.

    #import <Foundation/Foundation.h>
    
    // Function to swap values using pointers to pointers
    void swap(int **p, int **q) {
        int *temp = *p; // Store the value of *p in a temporary variable
        *p = *q;         // Assign the value of *q to *p
        *q = temp;       // Assign the value of temp to *q
    }
    
    int main(int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        // Declare two integer variables
        int a = 10, b = 20;
    
        // Declare pointers to hold the addresses of a and b
        int *p = &a, *q = &b;
    
        NSLog(@"Before Swapping");
        NSLog(@"Value of a = %d", a);
        NSLog(@"Value of b = %d", b);
    
        // Call the swap function, passing the addresses of p and q
        swap(&p, &q);
    
        NSLog(@"\nAfter Swapping");
        NSLog(@"Value of a = %d", *p);
        NSLog(@"Value of b = %d", *q);
    
        [pool drain];
        return 0;
    }

    Output:

    Before Swapping
    Value of a = 10
    Value of b = 20
    
    After Swapping
    Value of a = 20
    Value of b = 10

    Example 2: Using Pointer to Pointer for Dynamic Memory Allocation

    In this example, a pointer to pointer is used to dynamically allocate memory for an integer.

    #import <Foundation/Foundation.h>
    
    int main() {
        // Declare an integer variable
        int i = 5;
    
        // Pointer to an integer
        int *p;
    
        // Pointer to a pointer to an integer
        int **q;
    
        // Store the address of i in p
        p = &i;
    
        // Store the address of p in q
        q = &p;
    
        // Display values stored in i, p, and q
        NSLog(@"Value stored at i = %d", i);
        NSLog(@"Value stored at *p = %d", *p);
        NSLog(@"Value stored at **q = %d", **q);
    
        return 0;
    }

    Output:

    Value stored at i = 5
    Value stored at *p = 5
    Value stored at **q = 5
    4. Passing Pointers to Functions

    Pointers are an essential feature in Objective-C, allowing you to manipulate data stored in memory directly. Passing pointers to functions is a powerful technique that optimizes memory usage, reduces function call overhead, and improves code performance. In Objective-C, pointers are used to pass values to functions and retrieve results from functions.

    Types of Pointers

    In Objective-C, pointers can be categorized as:

    i. Constant Pointers: These pointers cannot be changed once initialized.
    2. Non-Constant Pointers: These pointers can have their values modified during the program’s execution.

    -(void) sampleFunction:(int *) inputPointer;
    -(int *) sampleFunctionOutput;

    Pointers are further divided into:

    • Input Pointers: These pointers are used to pass data to functions.
    • Output Pointers: These pointers are used to return data from functions.

    Syntax

    -(void) sampleFunction:(int *) inputPointer;
    -(int *) sampleFunctionOutput;

    Example 1: Passing a Pointer to a Function

    In this example, we demonstrate how to pass a pointer to a function and modify the value of the variable it points to.

    #import <Foundation/Foundation.h>
    
    @interface SampleClass : NSObject
    
    // Declare a method that accepts an int pointer as an argument
    -(void) sampleFunction:(int *) inputPointer;
    
    @end
    
    @implementation SampleClass
    
    -(void) sampleFunction:(int *) inputPointer {
        // Modify the value that inputPointer points to
        *inputPointer = 20;
    }
    
    @end
    
    int main() {
        int sampleValue = 10;
    
        // Create a pointer to sampleValue
        int *inputPointer = &sampleValue;
        SampleClass *obj = [[SampleClass alloc] init];
    
        // Pass the pointer to the function
        [obj sampleFunction:inputPointer];
    
        // Print the value of sampleValue after function call
        printf("Value after passing to function: %d\n", sampleValue);
        return 0;
    }

    Output:

    Value after passing to function: 20
    5. Return Pointer From Functions​

    A pointer is a variable or constant that stores the memory address of another variable. It must be declared before it can hold the address of a variable. The primary advantage of using pointers is that they help optimize program memory, provide direct access to memory locations, and enable faster program execution by allowing efficient data manipulation. Pointers also facilitate dynamic memory allocation, making them essential for file handling. Through pointers, we can symbolically represent memory locations. It is important to declare a pointer before using it to store an address.

    Returning a Pointer from Functions

    In Objective-C, like in other programming languages, you can return a pointer from user-defined functions. For this, you need to define a function that returns a pointer to a variable. The pointer’s data type must match the return type of the function. Also, the function used to return a pointer cannot have a void return type, even if the pointer to be returned is null.

    data_type* demoFunction() {
        // function code
    }

    Example:

    #import <Foundation/Foundation.h>
    
    /* Declaring a global variable */
    int number = 10;
    
    /* Function to return a pointer to a variable */
    int* getPointer() {
        int *ptr;
        ptr = &number;  // Assigning address of 'number' to pointer
        return ptr;     // Returning the pointer
    }
    
    int main() {
        // Declaring a pointer of type int
        int *ptr;
    
        // Calling the function and storing the returned pointer in 'ptr'
        ptr = getPointer();
    
        // Dereferencing the pointer to access the value it points to
        NSLog(@"The value pointed to by ptr is %d.", *ptr);
    
        return 0;
    }

    Output:

    The value pointed to by ptr is 10.
  • Arrays in Objective-C

    Arrays in detail

    An Array is a data structure that holds similar types of data in contiguous memory. In Objective-C, arrays are single-variable collections used to store multiple elements of the same type. They can be accessed using an index, and the concept is similar to arrays in the C programming language.

    Declaration of an Array

    To declare an array, you specify the data type, name, and size of the array. The syntax for declaring an array is as follows:

    type arr[size-of-array];

    Here:

    • type is any valid data type.
    • size-of-array specifies the number of elements the array can hold.

    For example:

    int arr[5];

    Example:

    // Objective-C program demonstrating an array
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
       NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
       // Declaring an integer array with a size of 5
       int arr[5] = {10, 20, 30, 40, 50};
       int i;
    
       // Accessing the array using a loop
       for (i = 0; i < 5; i++) {
            // Printing each array element
            printf("%d ", arr[i]);
       }
       [pool drain];
       return 0;
    }

    Output:

    10 20 30 40 50
    Initializing Arrays

    In Objective-C, arrays can be initialized either element by element or all at once.

    Element-by-Element Initialization:

    int ArrayName[3];
    ArrayName[0] = 45;

    All-at-Once Initialization:

    int ArrayName[5] = {2, 5, 7, 3, 2};

    If the size of the array is omitted, the compiler will create an array large enough to hold the initialization values:

    int arr[] = {55, 78, 89, 99, 250};

    Example 1:

    // Objective-C program demonstrating array initialization
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        // Initializing an array using curly braces
        int arr[5] = {33, 25, 45, 78, 88};
    
        // Printing each element of the array
        printf("%d ", arr[0]);
        printf("%d ", arr[1]);
        printf("%d ", arr[2]);
        printf("%d ", arr[3]);
        printf("%d ", arr[4]);
    
        [pool drain];
        return 0;
    }

    Output:

    33 25 45 78 88
    Accessing Array Elements

    You can access elements of an array using their indices. For example:

    int rollno = roll_no_array[2];

    Example:

    // Objective-C program to access array elements using indices
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        // Array declaration
        int roll_no_array[] = {55, 78, 89, 99, 250};
    
        // Accessing an element using its index
        int rollno = roll_no_array[2];
    
        // Printing the accessed element
        printf("Roll No is = %d ", rollno);
    
        [pool drain];
        return 0;
    }

    Output:

    Roll No is = 89
    Accessing Array Elements via Loops

    Using loops is an efficient way to access elements in an array, especially when the array has many elements.

    // Objective-C program to access array elements using a loop
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        // Array declaration
        int roll_no_array[5] = {55, 78, 89, 99, 250};
    
        // Accessing elements using a loop
        printf("Roll No is = ");
        for (int i = 0; i < 5; i++) {
            printf("%d ", roll_no_array[i]);
        }
    
        [pool drain];
        return 0;
    }

    Output:

    Roll No is = 55 78 89 99 250
  • Numbers in Objective-C

    Numbers in detail

    In Objective-C, numbers are treated as objects instead of primitive data types like in other programming languages. This allows for a greater range of values and offers various methods to work with numbers through the NSNumber class. These methods make number handling in Objective-C more flexible and powerful.

    Instead of using primitive data types such as intfloat, and double, Objective-C allows these types to be encapsulated as objects, providing additional functionality. Using NSNumber, you can perform a variety of mathematical operations and store numbers as objects, which can then be manipulated and returned using specific methods.

    Example 1: Addition of Two Numbers

    In this example, we create an NSNumber object for each number and then add them together. The result is also stored as an NSNumber object.

    #import <Foundation/Foundation.h>
    
    @interface MathOperations:NSObject
    - (NSNumber *)addNumber:(NSNumber *)a withNumber:(NSNumber *)b;
    @end
    
    @implementation MathOperations
    
    - (NSNumber *)addNumber:(NSNumber *)a withNumber:(NSNumber *)b {
       float num1 = [a floatValue];  // Extract the first number as a float
       float num2 = [b floatValue];  // Extract the second number as a float
       float sum = num1 + num2;     // Calculate the sum
       NSNumber *result = [NSNumber numberWithFloat:sum];  // Store the sum in an NSNumber
       return result;  // Return the result
    }
    
    @end
    
    int main() {
       @autoreleasepool {
           MathOperations *operations = [[MathOperations alloc] init];
           NSNumber *num1 = [NSNumber numberWithFloat:15.5];  // First number
           NSNumber *num2 = [NSNumber numberWithFloat:9.0];   // Second number
           NSNumber *sum = [operations addNumber:num1 withNumber:num2];  // Add the numbers
           NSString *sumString = [sum stringValue];  // Convert the result to a string for display
           NSLog(@"The sum is %@", sumString);  // Output the result
       }
       return 0;
    }

    Components of a For Loop:

    1. Initialization: Used to initialize counters or iterators (e.g., int counter = 1;).
    2. Condition: Determines how long the loop will run (e.g., counter <= 10;).
    3. Updation: Updates the counter or iterator after each iteration (e.g., counter++;).

    Examples:

    The sum is 24.5
    Methods for Working with Numbers in Objective-C

    The NSNumber class provides several methods that make working with numbers easier. These include:

    • (BOOL)boolValue: Converts the NSNumber to a boolean.
    • (float)floatValue: Converts the NSNumber to a float.
    • (NSString *)stringValue: Converts the NSNumber to a NSString.
    • (int)intValue: Converts the NSNumber to an int.
    • (NSNumber *)numberWithFloat:(float)value: Creates an NSNumber object with a float value.

    Objective-C also includes several mathematical functions, such as:

    • CEIL(): Returns the smallest integer greater than or equal to the given number.
    • COS(): Returns the cosine of a given number.
    • FLOOR(): Returns the largest integer less than or equal to the given number.
    • MOD(): Returns the remainder of dividing two numbers.
    • RAND(): Generates a random number.

    Example 2: Subtracting Two Numbers

    In this example, we will subtract two numbers, 100 and 40, and display the result.

    #import <Foundation/Foundation.h>
    
    @interface MathOperations:NSObject
    - (NSNumber *)subtractNumber:(NSNumber *)x fromNumber:(NSNumber *)y;
    @end
    
    @implementation MathOperations
    
    - (NSNumber *)subtractNumber:(NSNumber *)x fromNumber:(NSNumber *)y {
       float num1 = [x floatValue];  // Extract the first number as a float
       float num2 = [y floatValue];  // Extract the second number as a float
       float result = num1 - num2;   // Calculate the difference
       NSNumber *resultObj = [NSNumber numberWithFloat:result];  // Store the result as an NSNumber
       return resultObj;  // Return the result
    }
    
    @end
    
    int main() {
       @autoreleasepool {
           MathOperations *operations = [[MathOperations alloc] init];
           NSNumber *num1 = [NSNumber numberWithFloat:100.0];  // First number
           NSNumber *num2 = [NSNumber numberWithFloat:40.0];   // Second number
           NSNumber *difference = [operations subtractNumber:num1 fromNumber:num2];  // Subtract the numbers
           NSString *resultString = [difference stringValue];  // Convert the result to a string
           NSLog(@"The result is %@", resultString);  // Output the result
       }
       return 0;
    }

    Output:

    The result is 60
  • Blocks in Objective-C

    Blocks in Objective-C are a powerful tool that help simplify development by allowing you to write more concise and efficient code. Blocks are self-contained pieces of code that can be passed around and executed as objects. They are widely used in Objective-C for purposes such as callbacks, iterators, and passing data between objects.

    Blocks in Objective-C are similar to functions in that they take arguments, execute code, and return a value. However, they also have the added benefit of being assignable to variables and passed as arguments to methods. Blocks can access and modify variables in the scope in which they are defined, making them highly flexible.

    Types of Blocks

    1. Standard Blocks:

    Standard blocks are simple blocks that are declared using the ^ symbol. These blocks can be used to control the flow of execution, such as executing multiple pieces of code in sequence.

    Syntax of Standard Block:

    ^(int a, int b) {
        int c = a + b;
        return c;
    }
    2. Typed Blocks:

    Typed blocks are blocks with a specified return type and argument types. These blocks allow you to define behavior for specific types of data.

    Syntax of Typed Block:

    ^int(int a, int b) {
        int c = a + b;
        return c;
    }
    3. Autoreleasing Blocks:

    Autoreleasing blocks are blocks that are declared using the __autoreleasing keyword. These blocks are automatically released when they go out of scope, helping with memory management.

    Syntax of Autoreleasing Block:

    @autoreleasepool {
        ^int(int a) {
            int b = a + 1;
            return b;
        }
    }

    Example 1:

    // Standard Block
    int (^multiply)(int, int) = ^(int num1, int num2) {
        return num1 * num2;
    };
    int result = multiply(3, 5); // result is 15
    
    // Typed Block
    typedef int (^AdditionBlock)(int, int);
    AdditionBlock add = ^(int num1, int num2) {
        return num1 + num2;
    };
    int sum = add(3, 5); // sum is 8
    
    // Autoreleasing Block
    @autoreleasepool {
        NSString *string = @"Hello, world!";
        void (^printString)(void) = ^{
            NSLog(@"%@", string);
        };
        printString();
    }

    Output:

    Hello, world!

    In this example:

    • The multiply block is a standard block that takes two integer parameters and returns their product.
    • The add block is a typed block that is declared using typedef and takes two integers as parameters and returns their sum.
    • The printString block is an auto-releasing block, declared within an @autoreleasepool statement, that prints a string to the console.

    Example 2:

    #import <Foundation/Foundation.h>
    
    // Block with no parameters and no return value
    typedef void (^SimpleBlock)(void);
    
    // Block with one parameter and no return value
    typedef void (^ParameterBlock)(NSString *);
    
    // Block with no parameters and a return value
    typedef int (^ReturnBlock)(void);
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // SimpleBlock implementation
            SimpleBlock simpleBlock = ^{
                NSLog(@"Welcome to the World of Blocks!");
            };
            simpleBlock(); // Output: "Welcome to the World of Blocks!"
    
            // ParameterBlock implementation
            ParameterBlock parameterBlock = ^(NSString *name) {
                NSLog(@"Hello, %@!", name);
            };
            parameterBlock(@"Alice"); // Output: "Hello, Alice!"
    
            // ReturnBlock implementation
            ReturnBlock returnBlock = ^{
                return 42;
            };
            int result = returnBlock();
            NSLog(@"The result is %d", result); // Output: "The result is 42"
    
            // Addition Block implementation
            int (^AdditionBlock)(int, int) = ^(int a, int b) {
                return a + b;
            };
            int sum = AdditionBlock(3, 5);
            NSLog(@"The addition of 3 and 5 is %d", sum); // Output: "The addition of 3 and 5 is 8"
        }
        return 0;
    }

    Output:

    Welcome to the World of Blocks!
    Hello, Alice!
    The result is 42
    The addition of 3 and 5 is 8

    Explanation:

    1. SimpleBlock: A block with no parameters and no return value that outputs a simple message.
    2. ParameterBlock: A block that takes a string parameter and outputs a greeting message.
    3. ReturnBlock: A block that returns an integer value.
    4. AdditionBlock: A block that takes two integers as parameters, adds them together, and returns the sum.

  • Functions

    Defining and Calling Functions

    In Objective-C, functions are defined outside of any class or method and can be called from anywhere in the program where they are visible. Functions can accept parameters and return values.

    Defining Functions

    A function definition includes the return type, function name, and parameters (if any).

    // Function definition
    int add(int a, int b) {
        return a + b;
    }
    Calling a Function

    To call a function, simply use its name followed by arguments in parentheses.

    // Function call
    int result = add(5, 3);  // result is 8
    NSLog(@"The result is %d", result);

    Function Parameters and Return Values

    Functions can accept parameters and return values of various data types.

    Function with Parameters

    You can define a function with parameters to pass values to it.

    // Function with parameters
    void printGreeting(NSString *name) {
        NSLog(@"Hello, %@", name);
    }
    
    // Calling the function with an argument
    printGreeting(@"Alice");
    Function with Return Value

    A function can return a value using the return statement.

    // Function with a return value
    double multiply(double x, double y) {
        return x * y;
    }
    
    // Calling the function and storing the return value
    double product = multiply(4.5, 2.3);
    NSLog(@"The product is %f", product);
    Function with No Parameters and No Return Value

    You can also define a function with no parameters and no return value.

    // Function with no parameters and no return value
    void sayHello() {
        NSLog(@"Hello, world!");
    }
    
    // Calling the function
    sayHello();

    Function Pointers

    Function pointers are used to store the address of a function, allowing you to call a function indirectly.

    Declaring a Function Pointer

    To declare a function pointer, specify the return type, followed by (*pointerName), and the parameter list.

    // Declare a function pointer
    int (*operation)(int, int);
    Assigning a Function to a Function Pointer

    Assign a function to a function pointer by specifying the function’s name without parentheses.

    // Use the function pointer to call the function
    int sum = operation(10, 5);  // Calls the 'add' function
    NSLog(@"The sum is %d", sum);

    Example: Using Function Pointers

    Here’s a complete example demonstrating the use of function pointers:

    #include <Foundation/Foundation.h>
    
    // Define a function
    int add(int a, int b) {
        return a + b;
    }
    
    int subtract(int a, int b) {
        return a - b;
    }
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // Declare a function pointer
            int (*operation)(int, int);
    
            // Assign functions to the function pointer and call them
            operation = add;
            NSLog(@"Add: %d", operation(10, 5));  // Outputs 15
    
            operation = subtract;
            NSLog(@"Subtract: %d", operation(10, 5));  // Outputs 5
        }
        return 0;
    }
  • Loops in Objective-C Loops

    In programming, there are scenarios where you need to execute a specific block of code multiple times. Typically, program statements are executed in a linear sequence, where the first statement is followed by the second, and so forth. However, programming languages provide control structures to manage more complex execution flows.

    loop statement allows a specific block of code to be executed repeatedly based on a condition. Below is the general structure of a loop statement, which is common across most programming languages: Types of Loops

    Types of Loops

    For Loop in Objective-C

    The for loop in Objective-C is a control structure used for repeating a set of instructions for a specified number of iterations. Unlike while or do-while loops, the for loop allows variable initialization, condition checking, and variable updates all in a single line.

    Syntax:

    for (initialisation_of_expression; condition_of_expression; update_expression)
    {
        // Body of the loop
        // Instructions to execute
    }

    Components of a For Loop:

    1. Initialization: Used to initialize counters or iterators (e.g., int counter = 1;).
    2. Condition: Determines how long the loop will run (e.g., counter <= 10;).
    3. Updation: Updates the counter or iterator after each iteration (e.g., counter++;).

    Examples:

    #import <Foundation/Foundation.h>
    
    int main ()
    {
        NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
    
        int counter;
    
        for (counter = 1; counter <= 10; counter++)
        {
            NSLog(@"%d. Hello, World!", counter);
        }
    
        [myPool drain];
        return 0;
    }

    Output:

    1. Hello, World!
    2. Hello, World!
    3. Hello, World!
    4. Hello, World!
    5. Hello, World!
    6. Hello, World!
    7. Hello, World!
    8. Hello, World!
    9. Hello, World!
    10. Hello, World!

    Example 2: Breaking Out of a For Loop

    The break statement allows exiting the loop before the condition becomes false.

    #import <Foundation/Foundation.h>
    
    int main ()
    {
        NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
    
        int counter;
    
        for (counter = 1; counter <= 10; counter++)
        {
            NSLog(@"%d. Processing...", counter);
    
            if (counter == 7)
            {
                NSLog(@"Breaking out of the loop...");
                break;
            }
        }
    
        [myPool drain];
        return 0;
    }

    Output:

    1. Processing...
    2. Processing...
    3. Processing...
    4. Processing...
    5. Processing...
    6. Processing...
    7. Processing...
    Breaking out of the loop...

    Example 3: Nested For Loops

    This program demonstrates how nested loops work.

    #import <Foundation/Foundation.h>
    
    int main ()
    {
        NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
    
        int i, j;
    
        for (i = 1; i <= 3; i++)
        {
            NSLog(@"Outer loop iteration: %d", i);
    
            for (j = 1; j <= 5; j++)
            {
                NSLog(@"  Inner loop iteration: %d", j);
            }
        }
    
        [myPool drain];
        return 0;
    }

    Output:

    Outer loop iteration: 1
      Inner loop iteration: 1
      Inner loop iteration: 2
      Inner loop iteration: 3
      Inner loop iteration: 4
      Inner loop iteration: 5
    Outer loop iteration: 2
      Inner loop iteration: 1
      Inner loop iteration: 2
      Inner loop iteration: 3
      Inner loop iteration: 4
      Inner loop iteration: 5
    Outer loop iteration: 3
      Inner loop iteration: 1
      Inner loop iteration: 2
      Inner loop iteration: 3
      Inner loop iteration: 4
      Inner loop iteration: 5

    Example 4: For Loop with Multiple Variables

    This example shows a for loop that initializes and updates two variables simultaneously.

    #import <Foundation/Foundation.h>
    
    int main ()
    {
        NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
    
        int i, j;
    
        for (i = 1, j = 10; i <= 10 && j >= 1; i++, j--)
        {
            NSLog(@"i = %d and j = %d", i, j);
        }
    
        [myPool drain];
        return 0;
    }

    Output:

    i = 1 and j = 10
    i = 2 and j = 9
    i = 3 and j = 8
    i = 4 and j = 7
    i = 5 and j = 6
    i = 6 and j = 5
    i = 7 and j = 4
    i = 8 and j = 3
    i = 9 and j = 2
    i = 10 and j = 1
    Do-While Loop in Objective-C

    Just like other programming languages, Objective-C supports the do..while loop. A do..while loop is also known as an inverted while loop because, in a while loop, the condition is checked before executing the loop body. If the condition is false, the loop does not execute. However, in a do..while loop, the condition is evaluated at the end of the loop body, ensuring the body executes at least once, regardless of the test condition.

    Syntax:

    do {
        // Loop Body
        // Update Statement
    } while(expression);

    Parts of a Do-While Loop:

    1. Loop Body: Contains the statements or logic to be executed repeatedly.
    2. Update Statement: Modifies the loop control variable (e.g., incrementing or decrementing).
    3. Expression: A condition evaluated after the loop body. If true, the loop continues; if false, the loop terminates.

    How the Do-While Loop Works:

    1. The loop body executes once when the do block is encountered.
    2. Statements in the loop body run.
    3. The update statement executes.
    4. The test condition is evaluated. If true, the control flow returns to Step 2.If false, the loop ends, and control exits the loop.

    Example:

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int num = 8;
    
        // Do-While Loop
        do {
            // Loop Body
            NSLog(@"Loop is executing.");
    
            // Update Statement
            num++;
        } while (num < 10);
    
        [pool drain];
        return 0;
    }

    Output:

    Loop is executing.
    Loop is executing.

    Example 2:

    Objective-C program to print the multiplication table of 16:

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int num = 1;
        int res;
    
        // Do-While Loop
        do {
            // Loop Body
            res = 16 * num;
            NSLog(@"16 * %d = %d", num, res);
    
            // Update Statement
            num++;
        } while (num <= 16);
    
        [pool drain];
        return 0;
    }

    Output:

    16 * 1 = 16
    16 * 2 = 32
    16 * 3 = 48
    16 * 4 = 64
    16 * 5 = 80
    16 * 6 = 96
    16 * 7 = 112
    16 * 8 = 128
    16 * 9 = 144
    16 * 10 = 160
    16 * 11 = 176
    16 * 12 = 192
    16 * 13 = 208
    16 * 14 = 224
    16 * 15 = 240
    16 * 16 = 256
    While Loop in Objective-C

    In Objective-C, the while loop allows for repeating a statement or a group of statements as long as the specified condition evaluates to true. Unlike other loops, the while loop checks its condition before executing the loop body. This makes it ideal for situations where the number of iterations is not known beforehand. If the condition is true, the loop executes; if the condition is false, the loop exits.

    while(condition) {
        // Body
    }

    How the While Loop Works:

    1. The program encounters the while loop.
    2. The condition is evaluated. If the condition is true, control enters the loop body. If the condition is false, the loop exits.
    3. After executing the loop body, any necessary updates occur.
    4. Control returns to the condition check. Steps 2–3 repeat as long as the condition remains true.
    5. When the condition becomes false, the loop ends, and control moves to the next part of the program.

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int num = 8;
    
        // While loop execution
        while(num < 10) {
            NSLog(@"Loop is running.");
            num++;
        }
    
        [pool drain];
        return 0;
    }

    Output:

    Loop is running.
    Loop is running.

    Explanation:

    1. The variable num is initialized with 8.
    2. The while loop checks the condition (num < 10). For num = 8, the condition is true, so the loop body executes, printing “Loop is running,” and num is incremented to 9.. For num = 9, the condition is still true, and the loop executes again.
    3. When num = 10, the condition becomes false, and the loop ends.

    Example:

    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    
        int num = 1;
        int res;
    
        // While loop execution
        while(num <= 15) {
            res = 15 * num;
            NSLog(@"15 * %d = %d", num, res);
            num++;
        }
    
        [pool drain];
        return 0;
    }

    Output:

    15 * 1 = 15
    15 * 2 = 30
    15 * 3 = 45
    15 * 4 = 60
    15 * 5 = 75
    15 * 6 = 90
    15 * 7 = 105
    15 * 8 = 120
    15 * 9 = 135
    15 * 10 = 150
    15 * 11 = 165
    15 * 12 = 180
    15 * 13 = 195
    15 * 14 = 210
    15 * 15 = 225
    Nested loops in Objective-C

    Objective-C provides three fundamental repetition control structures, commonly known as loops. These loops enable programmers to repeatedly execute a single statement or a block of statements as long as a specified condition is met. Additionally, loops can be embedded within one another, a concept referred to as Nested Loops. Let’s explore them in detail.

    Objective-C supports three types of loops that can be nested:

    1. Nested While Loop
    2. Nested Do-While Loop
    3. Nested For Loop

    1. Nested While Loop: In Objective-C, a nested while loop occurs when one while loop is placed inside another. For every iteration of the outer loop, the inner loop executes completely, starting from its initial condition and continuing until its termination condition is satisfied.

    Syntax:

    // Outer while loop
    while (condition_expr_1)
    {
        // Inner while loop
        while (condition_expr_2)
        {
            // Statements executed by the inner loop
            statement_1;
    
            // Update the inner loop condition
            increment/decrement of condition_expr_2;
        }
    
        // Statements executed by the outer loop
        statement_3;
    
        // Update the outer loop condition
        increment/decrement of condition_expr_1;
    }

    Execution Flow of Nested While Loops

    Step 1: The control checks the condition of the outer while loop (condition_expr_1).

    Step 2: If condition_expr_1 is true:

    • The control enters the body of the outer loop.
    • The inner while loop condition (condition_expr_2) is checked.

    Step 3: The control enters the body of the outer loop. The inner while loop condition (condition_expr_2) is checked.

    Step 4: If condition_expr_2 is false, the control exits the inner loop and continues with the statements following it in the outer loop.

    Step 5: The outer loop condition (condition_expr_1) is updated and rechecked.

    Step 6: If condition_expr_1 is false, the control exits the outer loop and proceeds with the next statements in the program.

    Example:

    #import <Foundation/Foundation.h>
    
    int main ()
    {
        NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
    
        int i = 1;
        int j;
    
        // Outer while loop
        while (i <= 3)
        {
            // Message from outer while loop
            NSLog(@"%d. Message from outer while loop.", i);
    
            j = 1;
    
            // Inner while loop
            while (j <= 5)
            {
                // Message from inner while loop
                NSLog(@"    %d. Message from inner while loop.", j);
    
                // Update the inner while loop condition
                j++;
            }
    
            // Update the outer while loop condition
            i++;
        }
        [myPool drain];
        return 0;
    }

    Output:

    1. Message from outer while loop.
        1. Message from inner while loop.
        2. Message from inner while loop.
        3. Message from inner while loop.
        4. Message from inner while loop.
        5. Message from inner while loop.
    2. Message from outer while loop.
        1. Message from inner while loop.
        2. Message from inner while loop.
        3. Message from inner while loop.
        4. Message from inner while loop.
        5. Message from inner while loop.
    3. Message from outer while loop.
        1. Message from inner while loop.
        2. Message from inner while loop.
        3. Message from inner while loop.
        4. Message from inner while loop.
        5. Message from inner while loop.

    2. Nested Do-While Loop: Similar to a while loop, Objective-C allows you to nest two or more do-while loops within a program. The primary distinction between a while loop and a do-while loop is that a do-while loop executes its body at least once before checking its condition. In the case of nested loops, both the outer and inner do-while loops execute their bodies at least once, following the same basic logic as the while loop.

    Syntax

    // Outer do-while loop
    do
    {
        // Inner do-while loop
        do
        {
            // Statements executed by the inner do-while loop
            statement_1;
    
            // Update the inner do-while loop condition
            increment/decrement of condition_expr_2;
    
        } while (condition_expr_2);
    
        // Statements executed by the outer do-while loop
        statement_3;
    
        // Update the outer do-while loop condition
        increment/decrement of condition_expr_1;
    
    } while (condition_expr_1);

    Execution Flow of Nested Do-While Loops

    Step 1: The control enters the body of the outer do-while loop.
    Step 2: The control then enters the body of the inner do-while loop.
    Step 3: Execute the body of the inner loop.
    Step 4: Update the condition variables of the inner loop.
    Step 5: Check the condition of the inner do-while loop: If true it return to Step 2 and if false: Exit the inner loop and move to the next statements in the outer loop.
    Step 6: Update the condition variables of the outer loop.
    Step 7: Check the condition of the outer do-while loop. If condition is true then it returns to Step 1.If false: Exit the outer loop.

    Example:

    #import <Foundation/Foundation.h>
    
    int main ()
    {
        NSAutoreleasePool *myPool = [[NSAutoreleasePool alloc] init];
    
        int i = 1;
        int j;
    
        // Outer do-while loop
        do
        {
            // Message from outer do-while loop
            NSLog(@"%d. Message from outer do-while loop.", i);
    
            j = 1;
    
            // Inner do-while loop
            do
            {
                // Message from inner do-while loop
                NSLog(@"    %d. Message from inner do-while loop.", j);
    
                // Update the inner loop condition
                j++;
    
            } while (j <= 5);
    
            // Update the outer loop condition
            i++;
    
        } while (i <= 3);
    
        [myPool drain];
        return 0;
    }

    Output:

    1. Message from outer do-while loop.
        1. Message from inner do-while loop.
        2. Message from inner do-while loop.
        3. Message from inner do-while loop.
        4. Message from inner do-while loop.
        5. Message from inner do-while loop.
    2. Message from outer do-while loop.
        1. Message from inner do-while loop.
        2. Message from inner do-while loop.
        3. Message from inner do-while loop.
        4. Message from inner do-while loop.
        5. Message from inner do-while loop.
    3. Message from outer do-while loop.
        1. Message from inner do-while loop.
        2. Message from inner do-while loop.
        3. Message from inner do-while loop.
        4. Message from inner do-while loop.
        5. Message from inner do-while loop.