{"id":2991,"url":"https://github.com/supermarin/ObjectiveSugar","last_synced_at":"2025-08-03T12:31:54.015Z","repository":{"id":5594794,"uuid":"6801434","full_name":"supermarin/ObjectiveSugar","owner":"supermarin","description":"ObjectiveC additions for humans. Ruby style.","archived":true,"fork":false,"pushed_at":"2016-08-30T22:52:39.000Z","size":800,"stargazers_count":2167,"open_issues_count":26,"forks_count":190,"subscribers_count":84,"default_branch":"master","last_synced_at":"2024-10-19T14:48:07.542Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/supermarin.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-11-21T19:11:54.000Z","updated_at":"2024-09-23T20:50:06.000Z","dependencies_parsed_at":"2022-07-07T06:30:54.354Z","dependency_job_id":null,"html_url":"https://github.com/supermarin/ObjectiveSugar","commit_stats":null,"previous_names":["mneorr/objectivesugar"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarin%2FObjectiveSugar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarin%2FObjectiveSugar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarin%2FObjectiveSugar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supermarin%2FObjectiveSugar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/supermarin","download_url":"https://codeload.github.com/supermarin/ObjectiveSugar/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228543243,"owners_count":17934449,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:16:28.367Z","updated_at":"2024-12-07T00:31:10.460Z","avatar_url":"https://github.com/supermarin.png","language":"Objective-C","readme":"![logo](http://i.imgur.com/BvHpSz0.png)\n\n\u003e Write Objective C _like a boss_.\u003cbr/\u003e\n\nA set of functional additions for Foundation you wish you'd had in the first place.\n\n\n[![Build Status](https://travis-ci.org/supermarin/ObjectiveSugar.svg?branch=master)](https://travis-ci.org/supermarin/ObjectiveSugar)\n\n\n## Usage\n\n1. Install via [CocoaPods](http://cocoapods.org/)\n\t\n\t```\n\tpod 'ObjectiveSugar'\n\t```\n2. Import the public header\n\n\t```\n\t#import \u003cObjectiveSugar/ObjectiveSugar.h\u003e\n\t```\n\n\n## Documentation\n\n\n__NSNumber__ additions\n``` objc\n[@3 times:^{\n    NSLog(@\"Hello!\");\n}];\n// Hello!\n// Hello!\n// Hello!\n\n[@3 timesWithIndex:^(NSUInteger index) {\n    NSLog(@\"Another version with number: %d\", index);\n}];\n// Another version with number: 0\n// Another version with number: 1\n// Another version with number: 2\n\n\n[@1 upto:4 do:^(NSInteger numbah) {\n    NSLog(@\"Current number.. %d\", numbah);\n}];\n// Current number.. 1\n// Current number.. 2\n// Current number.. 3\n// Current number.. 4\n\n[@7 downto:4 do:^(NSInteger numbah) {\n    NSLog(@\"Current number.. %d\", numbah);\n}];\n// Current number.. 7\n// Current number.. 6\n// Current number.. 5\n// Current number.. 4\n\nNSDate *firstOfDecember = [NSDate date]; // let's pretend it's 1st of December\n\nNSDate *firstOfNovember = [@30.days since:firstOfDecember];\n// 2012-11-01 00:00:00 +0000\n\nNSDate *christmas = [@7.days until:newYearsDay];\n// 2012-12-25 00:00:00 +0000\n\nNSDate *future = @24.days.fromNow;\n// 2012-12-25 20:49:05 +0000\n\nNSDate *past = @1.month.ago;\n// 2012-11-01 20:50:28 +00:00\n```\n--\n__NSArray__ / __NSSet__ additions\n``` objc\n// All of these methods return a modified copy of the array.\n// They're not modifying the source array.\n\nNSArray *cars = @[@\"Testarossa\", @\"F50\", @\"F458 Italia\"]; // or NSSet\n\n[cars each:^(id object) {\n    NSLog(@\"Car: %@\", object);\n}];\n// Car: Testarossa\n// Car: F50\n// Car: F458 Italia\n\n[cars eachWithIndex:^(id object, NSUInteger index) {\n    NSLog(@\"Car: %@ index: %i\", object, index);\n}];\n// Car: Testarossa index: 0\n// Car: F50 index: 1\n// Car: F458 Italia index: 2\n\n[cars each:^(id object) {\n    NSLog(@\"Car: %@\", object);\n} options:NSEnumerationReverse];\n// Car: F458 Italia\n// Car: F50\n// Car: Testarossa\n\n[cars eachWithIndex:^(id object, NSUInteger index) {\n    NSLog(@\"Car: %@ index: %i\", object, index);\n} options:NSEnumerationReverse];\n// Car: F458 Italia index: 2\n// Car: F50 index: 1\n// Car: Testarossa index: 0\n\n[cars map:^(NSString* car) {\n    return car.lowercaseString;\n}];\n// testarossa, f50, f458 italia\n\n// Or, a more common example:\n[cars map:^(NSString* carName) {\n    return [[Car alloc] initWithName:carName];\n}];\n// array of Car objects\n\nNSArray *mixedData = @[ @1, @\"Objective Sugar!\", @\"Github\", @4, @\"5\"];\n\n[mixedData select:^BOOL(id object) {\n  return ([object class] == [NSString class]);\n}];\n// Objective Sugar, Github, 5\n\n[mixedData reject:^BOOL(id object) {\n    return ([object class] == [NSString class]);\n}];\n// 1, 4\n\nNSArray *numbers = @[ @5, @2, @7, @1 ];\n[numbers sort];\n// 1, 2, 5, 7\n\ncars.sample\n// 458 Italia\ncars.sample\n// F50\n\n```\n--\n__NSArray__ only\n``` objc\n\nNSArray *numbers = @[@1, @2, @3, @4, @5, @6];\n\n// index from 2 to 4\nnumbers[@\"2..4\"];\n// [@3, @4, @5]\n\n// index from 2 to 4 (excluded)\nnumbers[@\"2...4\"];\n// [@3, @4]\n\n// With NSRange location: 2, length: 4\nnumbers[@\"2,4\"];\n// [@3, @4, @5, @6]\n\nNSValue *range = [NSValue valueWithRange:NSMakeRange(2, 4)];\nnumbers[range];\n// [@3, @4, @5, @6]\n\n[numbers reverse];\n// [@6, @5, @4, @3, @2, @1]\n\n\nNSArray *fruits = @[ @\"banana\", @\"mango\", @\"apple\", @\"pear\" ];\n\n[fruits includes:@\"apple\"];\n// YES\n\n[fruits take:3];\n// banana, mango, apple\n\n[fruits takeWhile:^BOOL(id fruit) {\n    return ![fruit isEqualToString:@\"apple\"];\n}];\n// banana, mango\n\nNSArray *nestedArray = @[ @[ @1, @2, @3 ], @[ @4, @5, @6, @[ @7, @8 ] ], @9, @10 ];\n[nestedArray flatten];\n// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10\n\nNSArray *abc = @[ @\"a\", @\"b\", @\"c\" ];\n[abc join];\n// abc\n\n[abc join:@\"-\"];\n// a-b-c\n\nNSArray *mixedData = @[ @1, @\"Objective Sugar!\", @\"Github\", @4, @\"5\"];\n\n[mixedData detect:^BOOL(id object) {\n    return ([object class] == [NSString class]);\n}];\n// Objective Sugar\n\n\n\n// TODO: Make a better / simpler example of this\nNSArray *landlockedCountries = @[ @\"Bolivia\", @\"Paraguay\", @\"Austria\", @\"Switzerland\", @\"Hungary\" ];\nNSArray *europeanCountries = @[ @\"France\", @\"Germany\", @\"Austria\", @\"Spain\", @\"Hungary\", @\"Poland\", @\"Switzerland\" ];\n\n\n[landlockedCountries intersectionWithArray:europeanCountries];\n// landlockedEuropeanCountries = Austria, Switzerland, Hungary\n\n[landlockedCountries unionWithArray:europeanCountries];\n// landlockedOrEuropean = Bolivia, Paraguay, Austria, Switzerland, Hungary, France, Germany, Spain, Poland\n\n[landlockedCountries relativeComplement:europeanCountries];\n// nonEuropeanLandlockedCountries = Bolivia, Paraguay\n\n[europeanCountries relativeComplement:landlockedCountries];\n// notLandlockedEuropeanCountries = France, Germany, Spain, Poland\n\n[landlockedCountries symmetricDifference:europeanCountries];\n// uniqueCountries = Bolivia, Paraguay, France, Germany, Spain, Poland\n```\n--\n__NSMutableArray__ additions\n``` objc\nNSMutableArray *people = @[ @\"Alice\", @\"Benjamin\", @\"Christopher\" ];\n\n[people push:@\"Daniel\"]; // Alice, Benjamin, Christopher, Daniel\n\n[people pop]; // Daniel\n// people = Alice, Benjamin, Christopher\n\n[people pop:2]; // Benjamin, Christopher\n// people = Alice\n\n[people concat:@[ @\"Evan\", @\"Frank\", @\"Gavin\" ]];\n// people = Alice, Evan, Frank, Gavin\n\n[people keepIf:^BOOL(id object) {\n    return [object characterAtIndex:0] == 'E';\n}];\n// people = Evan\n\n```\n--\n__NSDictionary__ additions\n``` objc\nNSDictionary *dict = @{ @\"one\" : @1, @\"two\" : @2, @\"three\" : @3 };\n\n[dict each:^(id key, id value){\n    NSLog(@\"Key: %@, Value: %@\", key, value);\n}];\n// Key: one, Value: 1\n// Key: two, Value: 2\n// Key: three, Value: 3\n\n[dict eachKey:^(id key) {\n    NSLog(@\"Key: %@\", key);\n}];\n// Key: one\n// Key: two\n// Key: three\n\n[dict eachValue:^(id value) {\n    NSLog(@\"Value: %@\", value);\n}];\n// Value: 1\n// Value: 2\n// Value: 3\n\n[dict invert];\n// { 1 = one, 2 = two, 3 = three}\n\nNSDictionary *errors = @{\n    @\"username\" : @[ @\"already taken\" ],\n    @\"password\" : @[ @\"is too short (minimum is 8 characters)\", @\"not complex enough\" ],\n    @\"email\" : @[ @\"can't be blank\" ];\n};\n\n[errors map:^(id attribute, id reasons) {\n    return NSStringWithFormat(@\"%@ %@\", attribute, [reasons join:@\", \"]);\n}];\n// username already taken\n// password is too short (minimum is 8 characters), not complex enough\n// email can't be blank\n\n[errors hasKey:@\"email\"]\n// true\n[errors hasKey:@\"Alcatraz\"]\n// false\n```\n--\n__NSString__ additions\n``` objc\nNSString *sentence = NSStringWithFormat(@\"This is a text-with-argument %@\", @1234);\n// This is a text-with-argument 1234\n\n[sentence split];\n// array = this, is, a, text-with-argument, 1234\n\n[sentence split:@\"-\"]\n// array = this is a text, with, argument 1234\n\n[sentence containsString:@\"this is a\"];\n// YES\n\n[sentence match:@\"-[a-z]+-\"]\n// -with-\n```\n--\n__C__ additions\n``` objc\nunless(_messages) {\n    // The body is only executed if the condition is false\n    _messages = [self initializeMessages];\n}\n\nint iterations = 10;\nuntil(iterations == 0) {\n    // The body is executed until the condition is false\n    // 10 9 8 7 6 5 4 3 2 1\n    printf(\"%d \", iterations);\n    iterations--;\n}\nprintf(\"\\n\");\n\niterations = 10;\ndo {\n    // The body is executed at least once until the condition is false\n    // Will print: Executed!\n    printf(\"Executed!\\n\");\n} until(true);\n```\n\n## Contributing\n\nObjectiveSugar is tested with [Kiwi](https://github.com/allending/Kiwi), and tests are located in Example.\u003cbr/\u003e\nIf you plan on contributing to the project, please:\n\n  * Write tests\n  * Write documentation\n\n\n## Team\n\n- Marin Usalj [@supermarin](https://github.com/supermarin)\n- Neil Cowburn [@neilco](https://github.com/neilco)\n\n","funding_links":[],"categories":["Utility","Objective-C","IOS 或 OSX","etc"],"sub_categories":["Web View","Other free courses"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupermarin%2FObjectiveSugar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupermarin%2FObjectiveSugar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupermarin%2FObjectiveSugar/lists"}