Passing a method as a parameter type

As I delve into learning JavaScript from Objective-C, I find myself pondering whether it is possible to have a method with parameter types in Objective-C. Let's take the example of the findIndex() JavaScript function that identifies and returns the index of the first array element passing a specified test function. How could this be implemented in Objective-C using blocks, if at all?

If I were to create a class category for NSArray, how would I go about passing a block to a method and applying that condition to the NSArray itself? If this is not feasible, I am eager to understand the reasons behind it.

    var ages = [3, 10, 18, 20];

    function checkAdult(age) {
        return age >= 18;
    }

    function myFunction() {
        document.getElementById("demo").innerHTML = ages.findIndex(checkAdult);
    }

I came across a valuable piece of information on StackOverflow regarding block syntax, which might aid in understanding the implementation of the findIndex() function.

Block Syntax

  1. Block as a method parameter Template

    - (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
            // your code
    }
    

    Example

    -(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
            // your code
    }
    
  2. Block as a method argument Template

    [anObject aMethodWithBlock: ^returnType (parameters) {
        // your code
    }];
    

    Example

    [self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
        // your code
    }];
    
  3. Block as a local variable** Template

    returnType (^blockName)(parameters) = ^returnType(parameters) {
        // your code
    };
    

    Example

    void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
        // your code
    };
    
  4. Block as a typedef Template

    typedef returnType (^typeName)(parameters);
    
    typeName blockName = ^(parameters) {
        // your code
    } 
    


FindIndex() Definition

Array.prototype.findIndex ( predicate [ , thisArg ] )

NOTE predicate should be a function that accepts three arguments and returns a value that is coercible to the Boolean value true or false. findIndex calls predicate once for each element of the array, in ascending order, until it finds one where predicate returns true. If such an element is found, findIndex immediately returns the index of that element value. Otherwise, findIndex returns -1.

Answer №1

Equivalent code snippet in Objective-C:

@implementation NSArray (Extension)

- (NSUInteger)findIndexWithCondition:(BOOL (^)(id item, NSUInteger index, NSArray* array))condition {
    NSUInteger foundIndex = NSNotFound;
    if (condition != NULL) {
        for (NSUInteger i = 0; i < self.count; i++) {
            if (condition(self[i], i, self)) {
                foundIndex = i;
                break;
            }
        }
    }
    return foundIndex;
}

@end

It's worth noting the change in the default return value from -1 to NSNotFound because the index is unsigned.

Usage of the method:

NSUInteger indexFound = [@[@3, @10, @18, @20] findIndexWithCondition:^BOOL(id element, NSUInteger index, NSArray *array) {
    return [element integerValue] >= 18;
}];

You have the option to simplify by not including extra parameters, as demonstrated in this JavaScript-inspired implementation:

@implementation NSArray (Extension)

- (NSUInteger)findIndexWithPredicate:(BOOL (^)(id item))predicate {
    NSUInteger foundIndex = NSNotFound;
    if (predicate != NULL) {
        for (NSUInteger i = 0; i < self.count; i++) {
            if (predicate(self[i])) {
                foundIndex = i;
                break;
            }
        }
    }
    return foundIndex;
}

@end

NSUInteger indexFound = [@[@3, @10, @18, @20] findIndexWithPredicate:^BOOL(id element) {
    return [element integerValue] >= 18;
}];

An alternative approach without creating a custom category involves utilizing the enumerateObjectsUsingBlock: method:

__block NSUInteger indexToFind;
[@[@3, @10, @18, @20] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if ([obj integerValue] >= 18) {
        *stop = YES;
        indexToFind = idx;
    }
}];

Furthermore, there are options like C function pointers instead of blocks, but blocks offer more versatility.

Answer №2

Here is a solution I came up with that is similar to Boris's:

NSArray *numbers = @[@"3", @"10", @"18", @"20"];

BOOL(^check)(NSInteger integer) = ^BOOL(NSInteger integer) {
    if (integer >= 18) {
        return YES;
    }
    return NO;
};

NSInteger(^findIndex)(BOOL(^check)(), NSArray *array) = ^NSInteger(BOOL(^check)(), NSArray *array) {
    for (NSUInteger i = 0; i < array.count; i++) {
        NSInteger currentNumber = [array[i] intValue];
        if (check(currentNumber) == YES) {
            return i;
        }
    }

    return -1;
};

NSInteger resultIndex = findIndex(check, numbers);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you use yargs (npm package) to generate an error message when a command is not recognized?

Is it possible to have yargs with 2 commands? yargs .command('test-all','',handler) .command('test-file','',handler) .argv When the user inputs: node myapp.js other-command No error is thrown by yargs. What steps s ...

form submission issue with return false not working

Despite my efforts, the form still redirects to the page. I've been awake since 1AM trying to troubleshoot this issue! Please assist! function del_entry() { $('.delete_deal').submit(function() { var $g = $(this); ...

From navigating getElementByID to tackling getElementsByClassName while constructing multiple select elements: a guide

I am facing an issue with accessing multiple select elements that have the same options in Javascript. Despite having the same class, I am unable to retrieve the options using Javascript. When I attempted switching from getElementById to getElementsByClass ...

Avoiding console errors when a REST call fails

After conducting some research, it appears that achieving this is not possible. Therefore, I decided to seek advice. My current task involves making a REST GET call to check for the existence of a folder. If the folder does not exist, I create a new one; ...

Throw an error if the entry is not found in the Firebase database

I have an array containing various objects. Users should be able to access all objects using moduls/, and a specific one with moduls/$id. However, if the requested modul does not exist, the database should return an error to inform the client that there is ...

What is the best way to replace testcaferc.json browsers using the command line interface (CLI

Scenario: I am facing a situation where I aim to execute Testcafe in docker within a remote environment that necessitates running Testcafe through its command-line interface. I intend to utilize the .testcaferc file that I use for local testing to avoid m ...

Efficiently transferring data in segments within an HTML table using jQuery

My HTML code looks like this: <table id="library_info_tbl"> <thead> <th>Call No.</th> <th>Book</th> <th>Accession No.</th> <th>Status</th> </thead> <tbody& ...

Trying to update React and Electron, encountering the error message "global is not defined"

I have an Electron + React app that has not been updated in a couple of years, initially utilizing the following packages: "@rescripts/cli": "^0.0.13", "@rescripts/rescript-env": "^0.0.11", "electron": &quo ...

What is the best way to receive a callback when a user cancels a dialog box to choose a mobile app after clicking on

I am currently exploring HTML coding for mobile devices and looking to integrate map routing functionality. When it comes to mobile devices, utilizing the local app is the more practical option, and I have had success implementing this by modifying the l ...

React Router 4 - Optimizing Component Refresh by Remounting Instead of Re-Rendering

I am currently in the process of configuring a React project that utilizes React Router 4 ("react-router-dom": "^4.3.1"). Within this project, I have implemented a SideBar, a NavBar, and the main content section of the application which changes based on th ...

Fill up mongoose with data on 3 schemas

I have successfully populated 2 schema, but I am facing difficulty in populating the third schema. Here are the schemas: Member Schema var mongoose = require('mongoose'); var bcrypt = require('bcryptjs'); var Schema = mongoose.Schema ...

Risks associated with the use of Base64 encoded URLs in relation to security

When accessing my API from a web application, I'm using ajax to send get and post requests. Since I'm new to this, I'm curious about the security implications related to the content type being used. Currently, I know of two content types t ...

Numbering the items in ng-repeat directive

I am facing a challenge with my AngularJS directive that is recursively nested within itself multiple times. The issue lies in the fact that the names of items in ng-repeat conflict with those in the outer element, causing it to malfunction. To illustrate ...

Exploring the Fundamentals of Skinning Animation in WebGL using Three.js

I've been exploring various demos on skinning in Three.js, but I'm struggling to understand if the imported model itself needs to be animated or if it's already animating from the modeling software and we just manipulate it? For example, ta ...

Ways to retrieve information from a URL using the .get() method in a secure HTTPS connection

As I work on handling user input from a form using node.js, express, and bodyParser, I encounter an issue. Even after using console.log(req.body), the output is {}. This is puzzling as there is data in the URL when the form is submitted successfully at htt ...

How to properly format large numbers on the Y-Axis in IOS Core Plot

I need assistance with formatting large numbers to be displayed on the Y-axis of a plot. My goal is to convert 1000 to 1K, 10000 to 10K, 1000000 to 1M, and so on. Is it possible to achieve this using NSNumberFormatter? If not, I am open to alternative so ...

Zurb's Vertical Navigation Bar: A Stylish and Functional Design

I attempted to replicate the left navigation bar from this link: The responsive navigation bar and contents on the right caught my attention. Currently, I am working on a project that requires a similar navigation bar. While I am proficient in HTML and C ...

Utilizing Conditional Styling for an Array of Objects within a Textarea in Angular 6

My array contains objects structured as follows: list =[ { name:"name1", value:true } { name:"name2", value:false } { name:"name3", value:true } { name:"name4", value:false ...

Need to get an item from a collection at the library?

Is it possible to import and use an object from a library? For instance, suppose we have a file named data.js with the following content: return { "name": "Testing" } In the file index.js, could we do something like this: const data = require('. ...

trouble seeing images with an array input and ngFor in Angular

I am encountering issues while attempting to exhibit an array of images by their source link using ngFor. It seems like there are errors hindering the functionality! Below is the image HTML code located within my card component: <div class="Session-Pa ...