• Stars
    star
    250
  • Rank 162,397 (Top 4 %)
  • Language
    Objective-C
  • License
    Other
  • Created about 14 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Smalltalk-inspired collection utility methods and macros for Cocoa

MACollectionUtilities

MACollectionUtilities is a set of Smalltalk-inspired methods and macros on Cocoa collection classes, taking advantage of blocks. It is released under a BSD license.

Convenience Creators

MACollectionUtilities includes three macros to simplify creating arrays, sets, and dictionaries. These macros give you something similar to the collection literals found in other languages, rather than the unwieldy [NSArray arrayWithObjects:...] syntax that Cocoa provides.

  • ARRAY(a, b, c) - Create an NSArray that holds objects a, b, and c.
  • SET(a, b, c) - Like ARRAY, but creates an NSSet.
  • DICT(a, b, c, d) - Create an NSDictionary that holds a -> b and c -> d.

Note that DICT uses the IMO much more sensible key/value order instead of Cocoa's standard value/key order. Be aware.

Also note that these macros do not need, and you should not place, a nil at the end. They can detect the end of their arguments without your help.

Methods

Methods are provided on NSArray and NSSet to do mapping, filtering, and matching. When used on NSArray, the resulting array is in the same order as the original, and matching always finds the first object. NSSet is unordered and so is the result, and which matching object is found is undefined. These category methods are prefixed with ma_ to avoid conflicts with other category methods.

  • ma_map: - Call the block once for each object in the collection, and use the return values to create a new collection. Note that block must not return nil.
  • ma_select: - Call the block once for each object in the collection. Use the objects where the block returns YES to create a new collection.
  • ma_match: - Search for an object in the collection for which the block returns YES and return it.
  • ma_reduce:block: - Start an accumulated value with the first argument. Call the block on each element of the array, passing it that element and the accumulated value so far. Set the accumulated value to the result. Allows an arbitrary "summation" operation to be performed on an array.
  • ma_sorted: - Use the block as a comparator to sort the array. Unlike the built-in Cocoa methods, the comparator returns a single BOOL, indicating whether the two objects should be sorted in ascending order. Note that this is different from the normal Cocoa technique of returning ascending, descending, or equal. Due to this difference, the comparator will be called somewhat more often than with the standard Cocoa methods, since it sometimes needs to be called twice to fully detect the ordering of a pair of objects.
  • ma_do: - Call the block once for each object in the collection. No result is collected.

Helper macros

To simplify the use of the above methods, helper macros are provided. These macros take a collection as their first parameter and an expression as their second. The expression is used to create a block which is passed to the appropriate method. The parameter obj is implicitly created by most macros and can be used in the expression to refer to the individual objects.

  • The MAP, SELECT, MATCH, and DO macros all correspond to the methods of the same names.
  • The REJECT macro is equivalent to a SELECT except that it selects objects for which the expression is false.
  • The REDUCE macro takes three arguments: the collection, the initial value, and the expression to use for reduction. This macro implicitly creates parameters a (the accumulated value) and b (the object from the array).
  • The SORTED macro implicitly creates parameters a and b, and the second parameter should be an expression which evaluates to true if a should be sorted before b.

Examples

Take an array of strings and append a suffix:

NSArray *newArray = MAP(stringArray, [obj stringByAppendingString: suffix]);

Append a prefix instead:

NSArray *newArray = MAP(stringArray, [prefix stringByAppendingString: obj]);

Find text files in a directory:

NSArray *files = SELECT([[NSFileManager defaultManager] contentsOfDirectoryAtPath: path error: NULL],
                        [[obj pathExtension] isEqual: @"txt"]);

Find image files:

NSSet *extensions = SET(@"jpg", @"jpeg", @"tiff", @"png", @"pdf");
NSArray *files = SELECT([[NSFileManager defaultManager] contentsOfDirectoryAtPath: path error: NULL],
                        [extensions containsObject: [obj pathExtension]]);

Find the first string that starts with an asterisk:

NSString *asteriskString = MATCH(stringArray, [obj hasPrefix: @"*"]);

Concatenate all of the strings in an array:

NSString *concatenated = REDUCE(stringArray, @"", [a stringByAppendingString: b]);

Sum all of the lengths of the strings in an array:

NSNumber *sumObj = REDUCE(stringArray, nil, [NSNumber numberWithInteger: [a integerValue] + [b length]]);
NSUInteger sum = [sumObj integerValue];

Sort an array of strings ascending in order of string length:

NSArray *orderedArray = SORTED(array, [a length] < [b length]);

Parallel Enumeration

Sometimes it's useful to work on multiple arrays in parallel. For example, imagine that you have two arrays of strings and you want to create a third array that contains the contents of the two arrays combined into a single string. With MACollectionUtilities this is extremely easy:

NSArray *first = ARRAY(@"alpha", @"air", @"bicy");
NSArray *second = ARRAY(@"bet", @"plane", @"cle");
NSArray *words = MAP(first, [obj stringByAppendingString: EACH(second)]);
// words now contains alphabet, airplane, bicycle

The EACH macro depends on context set up by the other macros. You can only use it with the macros, not with the methods.

You can use multiple arrays with multiple EACH macros to enumerate several collections in parallel:

NSArray *result = MAP(objects, [obj performSelector: NSSelectorFromString(EACH(selectorNames))
                                         withObject: EACH(firstArguments)
                                         withObject: EACH(secondArguments)];

The EACH macro works by creating and tracking an NSEnumerator internally. It lazily creates the enumerator on the first use, and then uses nextObject at each call. Thus if your arrays are not the same length, it will begin to return nil, watch out.

Because they are unordered, parallel enumeration doesn't make sense for NSSet and EACH is not supported for them.

More Repositories

1

MAObjCRuntime

ObjC wrapper for ObjC runtime API
Objective-C
1,534
star
2

MAKVONotificationCenter

Better key-value observing for Cocoa
Objective-C
528
star
3

MAZeroingWeakRef

Zeroing weak references for retain/release Objective-C
Objective-C
361
star
4

MABlockClosure

ObjC block -> C function pointer using libffi
Objective-C
359
star
5

Circle

Objective-C
313
star
6

BinaryCoder

An example implementation of Swift.Codable using a simple binary format
Swift
168
star
7

memorydumper2

Swift
161
star
8

SwiftObserverSet

NSNotificationCenter re-conceptualization for Swift
Swift
132
star
9

MADispatchQueue

A spiritual reimplementation of the basics of dispatch_queue, for educational purposes
Objective-C
128
star
10

memorydumper

Swift
106
star
11

MAMirroredQueue

Objective-C
98
star
12

MAFuture

Proxying futures library for Objective-C
Objective-C
89
star
13

MAAsyncIO

GCD-based async IO
Objective-C
83
star
14

MAObject

Reimplementation of most NSObject functionality, for educational purposes
Objective-C
83
star
15

TSUD

Type-Safe User Defaults - Swifty NSUserDefaults wrapper
Swift
77
star
16

MABGTimer

Background timers, not associated with any thread, for Objective-C
Objective-C
71
star
17

iphone-user-performance-tests

A utility for doing simple tests of an iOS device's user-facing performance, and some collected results.
Swift
51
star
18

MAGenerator

Blocks/macros-based library for building Python-like generators in Objective-C
Objective-C
48
star
19

MABlockForwarding

Generic block forwarding, like forwardInvocation:
Objective-C
47
star
20

mikeash.com-svn

Legacy repository converted over from mikeash.com/svn/
Objective-C
43
star
21

PerformanceTest

Simple performance testing for various common operations in Mac/iOS programs
Objective-C++
40
star
22

DemoXcodePlugin

Objective-C
40
star
23

NSRectangle

Objective-C
39
star
24

XCommentWrap

Xcode extension for hard wrapping comments.
Swift
38
star
25

MANotificationCenter

NSNotificationCenter workalike, for education purposes
Objective-C
36
star
26

ChemicalBurn

Objective-C
35
star
27

MAInvocation

Reimplementation of NSInvocation, minus floating-point support, for educational purposes
Objective-C
35
star
28

MACollections

Reimplementation of some Cocoa collections, for educational purposes
Objective-C
35
star
29

GPULife

GPU-accelerated Game of Life screensaver
Objective-C
30
star
30

MAPlistTypeChecking

Conveniences for type-checking and reporting errors in plists, JSON, and other similar structures
Objective-C
26
star
31

MAAutoreleasePool

NSAutoreleasePool workalike for educational purposes
Objective-C
23
star
32

MASON

Friendly JSON decoding API for Swift
Swift
20
star
33

StringWithFormat

Reimplementation of stringWithFormat: for educational purposes
Objective-C
18
star
34

MADispatchGroup

Reimplementation of dispatch_group, for educational purposes.
Objective-C
12
star
35

MAParanoidAllocator

Objective-C
12
star
36

refcounting

Implementation of ObjC refcounting, for educational purposes
Objective-C
10
star
37

Smurf

A Swift library which renames Any to Smurf
Swift
9
star
38

sitescan

Python
5
star
39

Turmites

My Turmites screensaver, from the distant past
Objective-C
5
star
40

compressor

Simple Arduino audio compressor code
Arduino
4
star
41

creatures

My extremely, extremely old artificial life program
Objective-C
4
star
42

Centrifugal

Objective-C
2
star
43

BlockContextExecution

BlockContextExecution
Objective-C
2
star
44

pyunitcalc

Python
1
star