Giter Site home page Giter Site logo

jetoolkit's Introduction

JEToolkit

Version Platform License

JEToolkit is a collection of time-saving goodies for iOS development.

(I use this library in production code, so this repo is actively maintained.)

Now with Swift 1.2 support!

  • Added Swift function counterparts to some Objective-C methods/macros that also makes sense in Swift code.
  • Evertyhing is audited for nullability (nullable, nonnull, etc).
  • Objective-C-only projects will still benefit from all available features!

Modules Summary

  • JEToolkit/JEToolkit: Useful categories, functions, and macros for safety, convenience, and readability.
  • JEToolkit/JEDebugging: A performant, configurable debugging framework that outputs to the debugger console, to an in-app console view, and/or to log files.
  • JEToolkit/JESettings: A class-based wrapper to NSUserDefaults and keychain access. Lets you access key-values just by declaring properties.
  • JEToolkit/JEOrderedDictionary: An NSMutableDictionary subclass that remembers the order you inserted keys. Useful if you want to maintain chronological information or a constant ordering of keys.
  • JEToolkit/JEWeakCache: A thread-safe caching mechanism that is similar to NSCache. The difference is JEWeakCache only keeps a weak reference of the objects, that is, it will keep a reference of objects until nothing else is retaining them.

Use each submodule independently (via cocoapods) or link everything as a whole package!

The JEToolkit module contains utilities that once you start using, you can never program without. They're that useful!

Safer handling of NSNotifications (Objective-C and Swift)

Tired of writing a corresponding [NSNotificationCenter removeObserver:self] in dealloc? You can now add observers to NSNotificationCenter that automatically unregister themselves on deallocation. Here's an example usage:

// Obj-C
[self registerForNotificationsWithName:UIApplicationDidEnterBackgroundNotification
      targetBlock:^(NSNotification *note) {
          // do something...
}];
// Swift
self.registerForNotificationsWithName(UIApplicationDidEnterBackgroundNotification) { (note) in
    // do something...
}

Variants that let you pass in other parameters (such as object, targetQueue) are available as well!

Adding properties to categories (Objective-C only)

Objective-C normally doesn't allow declaring @properties to categories. The JESynthesize() macro lets you do exactly that by declaring the proper accessor and setter methods for you depending on the data type and the access modifier (assign, strong, etc) you set. And as an extension for associated objects, JESynthesize also supports weak (!!).

  • Provides a one-line declaration of properties in categories
  • Supports all access modifiers (assign, strong, etc) including weak!
  • Because the methods are generated at compile-time, you can get away without declaring any @property's at all.
  • Compile-time error checking to prevent mismatching access modifiers and data types (for example, setting strong on a CGRect type is not allowed)
// Obj-C
@implementation // ...

JESynthesize(assign, CGRect, frame, setFrame);
JESynthesize(strong, NSString *, name, setName);
JESynthesize(copy, void(^)(void), completion, setCompletion);
JESynthesize(unsafe_unretained, id, unsafeObject, setUnsafeObject);
JESynthesize(weak, id<UITableViewDelegate>, delegate, setDelegate);
JESynthesize(strong, NSString *, readonlyID, changeReadonlyID);

// ...

Asserting localized strings (Objective-C and Swift)

The JEL10n() function is a replacement for NSLocalizedString() that asserts the existence of a localization (l10n) string in a .strings file at runtime.

// Obj-C
label.text = JEL10n(@"myviewcontroller.label.title"); // load from Localizable.strings
label.text = JEL10nFromTable(@"CustomStrings", @"myviewcontroller.label.title"); // load from CustomStrings.strings
// Swift
label.text = JEL10n("myviewcontroller.label.title") // load from Localizable.strings
label.text = JEL10nFromTable("CustomStrings", "myviewcontroller.label.title") // load from CustomStrings.strings

Compile-time check of KVC keys (Objective-C only)

The JEKeypath(...) macro returns and checks existence of a KVC (or KVO) keypath during compile time. For KVC operators, you can also use the JEKeypathOperator(...) variant. If the keypath doesn't exist, compilation will fail.

// Obj-C
[obj setValue:@"John" forKey:JEKeypath(Person *, name)];
[obj setValue:@"John" forKey:JEKeypath(typeof(self), name)]; // typeof() operator
[obj setValue:@"John" forKey:JEKeypath(Person *, friend.name)]; // dot notation
NSArray *names = [friends valueForKeypath:JEKeypathOperator(unionOfObjects, Person *, name)];

Refactoring proeprty names is not scary anymore!

Elegant handling of weak-strong block capture (Objective-C only)

Tired of writing weakSelf, strongSelf, weakSomething, strongSomething, etc? With JEScopeWeak() and JEScopeStrong() you can turn this

// Obj-C
typeof(self) __weak weakSelf = self;
[request downloadSomethingWithCompletion:^{
    typeof(self) __strong strongSelf = weakSelf;
    [strongSelf doSomethingElse];
}];

to this

// Obj-C
JEScopeWeak(self);
[request downloadSomethingWithCompletion:^{
    JEScopeStrong(self);
    [self doSomethingElse];
}];

Breaking retain cycles without cluttering your code!

Automatic keyboard handling for scrollviews (Objective-C and Swift)

A UIScrollView category allows automatic handling of keyboard events, including auto-scrolling to descendant firstResponders. All you have to do is setup your scrollViews (or more commonly, tableViews) this way:

// Obj-C
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.scrollView addKeyboardObserver];
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.scrollView removeKeyboardObserver];
}
// Swift
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.scrollView.addKeyboardObserver()
}
override func viewWillDisappea(animated: Bool) {
    super.viewWillDisappear(animated)
    self.scrollView.removeKeyboardObserver()
}

And a whole lot more!

  • NSCache subscripting support similar to NSDictionary
  • NSDate, NSNumber, NSString, and NSDate utilities for converting to and from known data types
  • NSURL API for getting and setting extended attributes
  • UIColor creation from RGB or hex.
  • UILabel and UITextView utilities for computing sizes and heights for the display string
  • UITableView and UICollectionView utilities for type-safe dequeuing of cells
  • and really, still a lot more!

The JEDebugging module is a logging framework that will surely help you and your teammates (even the server guys and your testers!)

Main Features

  • Provides clean and readable logs. Log messages are indented and marked by log level-specific markers. This code:
// Obj-C
JELog(@"This is a sample log");
JELogNotice(@"This is a notice-level log");
JELogAlert(@"This is an alert-level log");
JEAssert(100 > 900, @"This is an assert failure log");
// Swift
JELog("This is a sample log")
JELogNotice("This is a notice-level log")
JELogAlert("This is an alert-level log")
JEAssert(100 > 900, "This is an assert failure log")

will print out this way:
Console screenshot

  • More informative debugDescriptions for common NSFoundation objects. For example, inspecting a dictionary using the lldb po command also tells what types the keys and values are (also note that NSNumbers show the actual data type of the stored value):
    Console screenshot
  • The awesome JEDump(...) macro lets you inspect and log anything you throw at it: ints, C arrays, structs, objects, blocks, etc. Check out the JEToolkitTests unit test or the JEToolkitDemo project to view more sample outputs and sample usages.
  • All logging are thread-safe.
  • Option to save logs to files. Log files are separated by date, and there is an API to enumerate the logs' NSDatas or NSURLs.
  • Option to display a lightweight, inline HUD console from within the app itself.
    Inline HUD screenshot
    By default, this view will not be created in release mode. You can expand/collapse the HUD with a draggable button, and you can stretch the size of the view. The HUD also stays on top of all other views/windows, even if you open a modal view or if you create your own window. There is also a button to send log files via UIActivityViewController (Air-Drop is a godsend!), as well as a button to clear all displayed logs.
  • Configurable settings for the console logger, the file logger, and the HUD logger.

The JESettings module provides cool base classes for managing NSUserDefaults and keychain data with object models. To create such models, subclass JEUserDefaults or JEKeychain and declare the data you want to manage as dynamic properties (@dynamic in Objective-C, @NSManaged in Swift)

// Obj-C
// .h
@interface MyUserDefaults: JEUserDefaults
    @property (nonatomic, strong) NSString *myString;
    @property (nonatomic, assign) NSInteger myNumber;
@end
// .m
@implementation MyUserDefaults
    @dynamic myString;
    @dynamic myNumber;
@end
// Swift
class MyUserDefaults: JEUserDefaults {
    @NSManaged var myString: String?
    @NSManaged var myNumber: Int
}

Once your model class is set up, you can start using right away. The code below,

// Obj-C
MyUserDefaults *defaults = [MyUserDefaults new];
defaults.myString = @"sample string";
defaults.myNumber = 42;
// Swift
let defaults = MyUserDefaults()
defaults.myString = "sample string"
defaults.myNumber = 42

saves these values to the NSUserDefaults:

"MyUserDefaults.myString" = "sample string"
"MyUserDefaults.myNumber" = 42

Isn't that cool?

Main Features

  • Supports all dynamic properties of the following types:
    • Objective-C
      • All primitive integral types (short, int, NSInteger, NSUInteger long long int, unsigned long long int, etc.)
      • All primitive boolean types (bool, BOOL)
      • All primitive floating-point types (float, double, CGFloat)
      • NSString *
      • NSNumber *
      • NSDate *
      • NSData *
      • NSURL *
      • NSUUID *
      • id<NSCoding> (Basically, anything that conforms to NSCoding protocol)
      • Class
      • SEL
      • CGPoint
      • CGSize
      • CGRect
      • CGAffineTransform
      • CGVector
      • UIEdgeInsets
      • UIOffset
      • NSRange
    • Swift
      • All types supported by Objective-C above
      • All string types bridgable to NSString (NSString?, String, String?)
      • All number types bridgable to NSNumber (NSNumber?, Int, Int32, UInt8, Double, CGFloat etc.)
  • By default, JEUserDefaults uses string keys in the format "<class name>.<property name>", but you can also configure your own format by overriding -[JEUserDefaults userDefaultsKeyForProperty:].
  • JEUserDefaults instances are created as singletons unique to each class and suiteName. See the header documentation for -[JEUserDefaults init] and -[JEUserDefaults initWithSuiteName:] for more details.
  • JEUserDefaults also lets you set default values for when the key doesn't exist in the NSUserDefaults. You can do this by getting a proxy instance with the proxyForDefaultValues method:
// Obj-C
MyUserDefaults *defaults = [MyUserDefaults new];

MyUserDefaults *fallback = [defaults proxyForDefaultValues];
fallback.myString = @"sample string";

defaults.myString = nil;

NSString *value = defaults.myString; // value is now "sample string"
// Swift
let defaults = MyUserDefaults()

let fallback = defaults.proxyForDefaultValues()
fallback.myString = "sample string"

defaults.myString = nil

let value = defaults.myString // value is now "sample string"

Internally, this just saves the default values with -[NSUserDefaults registerUserDefaults:] ;)

  • By default, JEKeychain uses the app bundle identifier as kSecAttrService, but you can pass a preferred service name to -[JEKeychain initWithService:accessGroup:].
  • By default, JEKeychain uses the property name as kSecAttrAccount, but you can also configure your own format by overriding -[JEKeychain keychainAccountForProperty:].
  • JEKeychain allows setting access modes (such as JEKeychainAccessAfterFirstUnlock, etc.) per property by overriding -[JEKeychain keychainAccessForProperty:].
  • If the JEDebugging module is included in the project, printing JEUserDefaults and JEKeychain instances using lldb's po command will print all keys and values saved.

Installation

  • Requires iOS 7 SDK and above
  • Requires ARC

Install via Cocoapods (Objective-C only)

pod 'JEToolkit', '~> 2.0'

Unfortunately, Cocoapod's Swift support requires the library to be compiled as a Framework, which isn't supported on iOS 7. Thus, Swift files were intendedly not included in JEToolkit's podspec so that Objective-C-only projects can still use JEToolkit as a static library, and without requiring the Swift runtime. To use with Swift, install as a submodule.

Install manually

The recommended way to add manually is to install as a git submodule.

git submodule add https://github.com/JohnEstropia/JEToolkit.git <destination directory>

You can also clone the repository independent to the app .xcodeproj directory, then drag and drop JEToolkit.xcodeproj to your app project.

Contributions?

Feel free to report any issues or send suggestions! 日本語で連絡していただいても構いません!

License

JEToolkit is released under an MIT license. See the LICENSE file for more information

jetoolkit's People

Contributors

johnestropia avatar

Watchers

James Cloos avatar edgency avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.