tools and practices for rapid application development
TRANSCRIPT
Balsamiq mockups
• Wireframes and navigation
flows
• UX + imagination
• Native iOS UI element
templates
• Fast- and easy wire-framing
Sketch3• Made for iOS designs
• Native iOS UI element
templates
• Complete toolset for mobile
design
• Similar parameters to
Interface Builder’s
• Screen-, app icon-, splash,
app store image design
• Export support for every
scale
photo: softpedia
Paintcode 2
• Drawing to code
• Solves complex & custom
drawing issues
• implements UI in DrawRect
photo: engadget
Danger• Can’t understand
• Lots of issues
• Not actively maintained
• You could write it better
• Overkill
• Fails at 90% completion
• Leaks
• Retain cycles
• Conflicts with other libs
Fabric (Crashlytics)
• App analytics tool
• Easy to integrate from code
• Easy to join as tester
• Per version crash reports
• Plugins
• Twitter Kit, MoPub, Digits
• Free (for basic usage)
Parse
• Simple remote data store
service
• Easy remote logging
• Flexible table content
• Statistics and analytics
• Push notification services
• Free (for basic usage)
Drupal
• PHP based community
driven CMS
• Easy to install
• “Click monkey” solution
• Out of the box REST with
session handling and OAuth
• Plugin support
• Free
• drupalgardens.com,
simplytest.me
Launchkit
• Before launch services
• Screenshot Builder
• App landing page
• Review monitor
• Sales reports
Deep mutable dictionary
NSMutableDictionary *responseMutable = (NSMutableDictionary
*)CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
(CFDictionaryRef)nonMutableDictionary, kCFPropertyListMutableContainers));
Trigger screen rotation
manually
[[UIDevice currentDevice]setValue:@(UIInterfaceOrientationPortrait)
forKey:@"orientation"];
Calling self from a block
__weak typeof(self) weakSelf = self;
[self.doSomething completion:^(id result, BOOL success)
{
__strong typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf)
{
[strongSelf processResult:result];
}
}];
Trigger button actions in a
cell// Create the tap action handler block
typedef void (^buttonTapActionBlock) (UITableViewCell*, BOOL);
@interface CustomUITableViewCell : UITableViewCell
// Create a property copied in your cell's class
@property (nonatomic, copy) buttonTapActionBlock firstButtonTapActionBlock;
@end
// Implement the tap action in cellForRowAtIndexPath
__weak typeof(self) weakSelf = self;
commentStickerCell.firstButtonTapActionBlock = ^(UITableViewCell* cell, BOOL isSelected)
{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf)
{
[strongSelf firstButtonTappedOnCell:cell withButtonSelection:isSelected];
}
};
- (void)firstButtonTappedOnCell:(UITableViewCell*)cell withButtonSelection:(BOOL)isSelected
{
NSIndexPath* cellIndexPath = [self.tableView indexPathForCell:cell];
Model* triggeredModel = self.modelArray[cellIndexPath.row];
[triggeredModel doSomething];
}
Multiple storyboards
connected in IB@implementation AOLinkedStoryboardSegue
+ (UIViewController *)sceneNamed:(NSString *)identifier
{
NSArray *info = [identifier componentsSeparatedByString:@"@"];
NSString *storyboard_name = info[1];
NSString *scene_name = info[0];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboard_name
bundle:nil];
UIViewController *scene = nil;
if (scene_name.length == 0) {
scene = [storyboard instantiateInitialViewController];
}
else {
scene = [storyboard instantiateViewControllerWithIdentifier:scene_name];
}
return scene;
}
- (id)initWithIdentifier:(NSString *)identifier
source:(UIViewController *)source
destination:(UIViewController *)destination
{
return [super initWithIdentifier:identifier
source:source
destination:[AOLinkedStoryboardSegue sceneNamed:identifier]];
}
- (void)perform
{
UIViewController *source = (UIViewController *)self.sourceViewController;
[source.navigationController pushViewController:self.destinationViewController
animated:YES];
}
@end
Multiple storyboards
connected in IB@implementation AOLinkedStoryboardSegue
+ (UIViewController *)sceneNamed:(NSString *)identifier
{
NSArray *info = [identifier componentsSeparatedByString:@"@"];
NSString *storyboard_name = info[1];
NSString *scene_name = info[0];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboard_name
bundle:nil];
UIViewController *scene = nil;
if (scene_name.length == 0) {
scene = [storyboard instantiateInitialViewController];
}
else {
scene = [storyboard instantiateViewControllerWithIdentifier:scene_name];
}
return scene;
}
- (id)initWithIdentifier:(NSString *)identifier
source:(UIViewController *)source
destination:(UIViewController *)destination
{
return [super initWithIdentifier:identifier
source:source
destination:[AOLinkedStoryboardSegue sceneNamed:identifier]];
}
- (void)perform
{
UIViewController *source = (UIViewController *)self.sourceViewController;
[source.navigationController pushViewController:self.destinationViewController
animated:YES];
}
@end
http://spin.atomicobject.com/2014/03/06/multiple-ios-storyboards/
DetailViewController@NotTheSameStoryBoard
NSHipster
Where to look
Cocoacontro
ls
Dave Verwerraywenderlic
h.com
Github
NSHipster
Where to look
Cocoacontro
ls
Dave Verwerraywenderlic
h.com
Github
NSHipster
Where to look
Cocoacontro
ls
Dave Verwer
raywenderlic
h.com
Github