Nullability Annotations

_Nullable -can have a nil value
-Nonnull -not expected to be nil

@interface Book : NSObject

@property (nonatomic, copy) NSString *title;
@property (nonatomic) Person *author;
@property (nonatomic) Person *editor;
@property (nonatomic) int yearOfPublication;

-(instancetype)initWithTitle:(NSString*)title
	author:(Person*)author
	year:(int)year;

@end

Code for the NSCoding Protocol

class Gif: NSObject, NSCoding {
	let url: NSURL
	let videoURL: NSURL
	let caption: String?
	let gitImage: UIImage
	var gifData: NSData?

	init(url: NSURL, videoURL: NSURL, caption: String?){
		self.url = url
		self.videoURL = videoURL
		self.caption = caption
		self.gifImage = UIImage.gifWithURL(url.absoluteString)!
		self.gifData = nil
	}

	required init?(coder decoder: NSCoder){
		self.url = decoder.decodeObjectForKey("url") as! NSURL
		self.videoURL = decoder.decodeObjectForKey("videoURL") as! NSURL
		self.caption = decoder.decodeObjectForKey("caption") as? String
		self.gifImage = decoder.decodeObjectForKey("gifImage") as! UIImage
		self.gifData = decoder.decodeObjectForKey("gifData") as? NSData
	}

	func encodeWithCoder(coder: NSCoder){
		coder.encodeObject(self.url, forKey: "url")
		coder.encodeObject(self.videoURL, forKey: "videoURL")
		coder.encodeObject(self.caption, forKey: "caption")
		coder.encodeObject(self.gifImage, forKey: "gifImage")
		coder.encodeObject(self.gifData, forKey:"gifData")
	}
}

create the file path

var gifsFilePath: String {
	let directories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
	let documentsPath = directories[0]
	let gifsPath = documentsPath.stringByAppendingString("/savedGifs")
	return gifsPath
}
var gif: Gif?
@IBOutlet weakl var gifImageView: UIImageView!

override func viewDidLoad(){
	super.viewDidLoad()
	gifImageView.image = gif?.gifImage
}

@IBAction func sharedGif(sendr: UIButton){
	var itemsToShare = [NSData]()
	itemsToShare.append((self.gif?gifData)!)

	let activityVC = UIActivityViewController(activityItems: itemsToShare, applicationActivities: nil)
	activityVC.completionWithItemsHandler = {(activity, comleted, items, error) in:
		if (completed){
			self.dismissViewControllerAnimated(true, completion: nil)
		}
	}
	presentViewController(activityVC, animated: true, completion:nil)
}

Enable Video Trimming

imagePicker property settings

func imagePicker(source:UIImagePickerControllerSourceType) -> UIImagePickerController {
	let picker = UIImagePickerController()
	picker.sourceType = source;
	picker.mediaTypes = [kUTTypeMovie as String]
	picker.allowsEditing = true;
	picker.delegate = self;

	return picker
}
func imagePicker(source:UIImagePickerControllerSourceType) -> UIImagePickerController {
	let picker = UIImagePickerController()
	picker.sourceType = source;
	picker.mediaTypes = [kUTTypeMovie as String]
	picker.allowsEditing = true;
	picker.delegate = self;

	return picker	
}

func convertVideToGIF(videoURL: NSURL, start: NSNumber?, duration: NSNumber?){
	dispatch_async(dispatch_get_main_queue()){
		self.dismissViewControllerAnimated(true, completion: nil)
	}

	let regift: Regift;

	if let start = start {
		regift = Regift(sourceFileURL: videoURL, destinationFileURL: nil, startTime: start.floatValue, duration: duration!.floatValue, frameRate: frameRate, loopCount: loopCount)
	} else {
		// Untrimmed
		regift = Regift(sourceFileURL: videoURL, destinationFileURL: nil, frameCount: frameCount, delayTime: delayTime, loopCount: loopCount)
	}

	let gifURL = regif.createGif()
	let gif = Gif(url: gifURL!, rawVideoURL: videoURL, caption: nil)
	displayGIF(gif)
}

public func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo
	info: [String : AnyObject]){
	let mediaType = info[UIImagePickerControllerMediaType] as! String

	if mediaType == kUTTypeMovie as String {

		let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
		let start: NSNumber? = info["_UIImagePickerControllerVideoEditingStart"] as? NSNumber
		let end: NSNumber? = info["_UIImagePickerControllerVideoEditingEnd"] as? NSNumber	
		var duration: NSNumber?
		if let start = start {
			duration = NSNumber(float: (end!.floatValue) - (start.floatValue))
		} else {
			duration = nil
		}
		convertVideoToGIF(videoURL, start: start, duration: duration)
	}	
}

Make room for keyboard

// Methods to adjust the keyboard
extension GiftEditorViewController {
	func subscribeToKeyboardNotifications(){
		NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GiftEditorViewController.keyboardWillShow(_:)),
			name: UIKeyboardWillShowNotification,
			object: nil)
		NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(GiftEditorViewController.keyboardWillHide(_:)),
			name: UIKeyboardWillHideNotification,
			object: nil)

	}

	func unsubscribeFromKeyboardNotifications(){
		NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
		NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
	}

	func keyboardWillShow(notification: NSNotification){
		if view.frame.origin.y >= 0 {
			view.frame.origin.y -= getKeyboardHeight(notification)
		}
	}

	func getKeyboardHeight(notification: NSNotification) -> CGFloat{
		let userInfo = notification.userInfo
		let keyboardSize = userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue
		return keyboardSize.CGRectValue().height
	}
}

Share the GIF

@IBAction func shareGif(sender: AnyObject){
	let url: NSURL = (self.gif?.url)!
	let animatedGIF = NSData(contentsOfURL: url)!
	let itemsToShare = [animatedGIF]

	let activityVC = UIActivityViewController(activityItems: itemToShare, applicationActivities: nil)

	activityVC.completionWithItemsHandler = {(activity, completed, items, error) in
		if(completed){
			self.navigationController?.popToRootViewControllerAnimated(true)
		}
	}

	navigationController?.presentViewController(activityVC, animated: true, completion: nil)
}

Create an Action Sheet

@IBAction func presentVideoOptions(){
	if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.Camera){
		//launchPhotoLibrary()
	} else {

		let newGifActionSheet = UIAlertController(title: "Create new GIF", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)

		let recordVideo = UIAlertAction(title: "Record a Video", style: UIAlertActionStyle.Default, handler: {
			(UIAlertAction) in self.launchVideoCamera()
			})
	}
}

Implement Regift Methods

import Foundation
import UIKit
import MobileCoreServices

// Regift constants
let frameCount = 16
let delayTime: Float = 0.2
let loopCount = 0 // 0 means loop forever

extension UIViewController: UIImagePickerDelegate, UINavigationControllerDelegate {
	
	@IBAction func launchVideoCamera(sender: AnyObject){
		let recordVideoController = UIImagePickerController()
		recordVideoController.sourceType = UIImagePickerControllerSourceType.launchVideoCamera
		recordVideoController.mediaTypes = [kUTTypeMovie as String]
		recordVideoController.allowsEditing = false
		recordVideoController.delegate = self

		presentViewController(recordVideoController, animated: true, completion: nil)
	}
	public func imagePickereController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
		let mediaType = info[UIImagePickerControllerMediaType] as! String

		if mediaType == kUTTypeMovie as String {
			let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
			dismissViewControllerAnimated(true, completion: nil)
			UISaveVideoAtPathToSavedPhotosAlbum(videoURL.path!, nil, nil, nil)
		}
	}

	public func imagePickerControllerDidCancel(picker: UIImagePickerController){
		dismissViewControllerAnimated(true, completion: nil)
	}

	func convertVideoToGIF(videoURL: NSURL){
		let regift = Regift(sourceFileURL: videoURL, frameCount: frameCount, delayTime: delayTime, loopCount: loopCount)
	}
}
#import <UIKit/UIKit.h>
#import "Gif.h"

@interface GifEditorViewController : UIViewController<UITextFiledDelegate>

@property (nonatomic) Gif *gif;
@property (weak, nonatomic) IBOutlet UIImageView *gifImageView;

@end

Rewriting the Gif Class

@interface Gif : NSObject <NSCoding>

@property (nonatomic) NSURL *url;
@property (nonatomic) NSString *caption;
@property (nonatomic) UIImage *gifImage;
@property (nonatomic) NSURL *videoURL;
@property (nonatomic) NSData *gifData;

-(instancetype)initWithGifUrl: (NSURL*)url videoURL:(NSURL*)videoURL caption:(NSString*)caption;
-(instancetype)initWithName:(NSString*)name;
@end

UIViewController Extension

// Mark: -UIViewController: UINavigationControllerDelegate

extension UIViewController: UINavigationControllerDelegate {}

// Mark: -UIViewController: UIImagePickerControllerDelegate

extension UIViewController: UIImagePickerControllerDelegate {
	
	public func imagePickerController(picker: UIImagePickerController,
		didFinishPickingMediaWithInfo info: [String : AnyObject]){
		let mediaType = info[UIImagePickerControllerMediaType] as! String

		if mediaType == kUTTypeMovie as String {
			let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL
		}
	}

	public func imagePickerControllerDidCancel(picker: UIImagePickerController){
		dismissViewControllerAnimated(true, completion: nil)
	}
}

Display a GIF in a UIImage

#import "WelcomViewController.h"
#import "UIViewController+Record.h"

@interface WelcomeviewController()

@property (nonatomic) NSURL *squareURL;

@end

@implementation WelcomeviewController

- (void)viewWillAppear:(BOOL)animated {
	[super viewWillAppear:animated];

	Gif *firstLaunchGif = [[Gif alloc] initWithName:@"tinaFeyHiFive"];
	self.defaultGifImageView.image = firstLaunchGif.gifImage;

	[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WelcomeViewSeen"];
}

@end

WelcomeViewController

import UIKit

class WelcomViewController: UIViewController {
	
	@IBOutlet weak var gifImageView: UIImageView!

	override func viewWillAppear(animated: Bool){
		// Return an animated UIImage
	}

	override func viewDidLoad(){
		super.viewDidLoad()

		// Do any additional setup after loading the view.
	}

	override func didReceiveMemoryWarning(){
		super.didReceiveMemoryWarning()
		// Dispose of any resources that can be recreated.
	}
}

Control Flow

-(Move)generateMove {
	NSUInteger randomNumber = arc4random_uniform(3);

	swtich(randomNumber){
		case 0:
			return Rock;
			break;
		case 1:
			return Paper;
			break;
		case 3:
			return Scissors;
			break;
		default:
			return Invalid;
			break;
	}

	// placeholder
	return Rock;
}
-(BOOL)defeats:(RPSTurn *)opponent {
	if ((self.move == Paper && opponent.move == Rock) ||
		(self.move == Scissors && opponent.move == Papper) ||
		(self.move == Rock && opponent.move == Scissors))
	{
		return true;
	} else {
		return false;
	}
}

Present Video Camera

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) NSMutableArray *gifs;
@end

#import "UIViewController+Record.h"
#import "GifEditorViewController.h"

#import <MobileCoreServices/MobileCoreServices.h>
#import <AVFoundation/AVFoundation.h>

#import "GifMaker_Objc-Swift.h"

@implementation UIViewController (Record)

static int constt kFrameCount = 16;
static const float kDelayTime = 0.2;
static const int kLoopCount = 0;

- (IBAction)presentVideoOptions:(id)sender {
	if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
	{
		[self launchPhotoLibrary];
	} else {
		UIAlertController *newGifActionSheet = [UIAlertController
			alertControllerWithTitle:@"Create new GIF"]
	}
}

@implementation UIViewController (Record)

static int const kFrameCount = 16;
static const float kDelayTime = 0.2;
static const int kLoopCount = 0;

- (IBAction)presentVideoOptions:(id)sender{
	if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
	{
		[self launchPhotoLibrary];
	} else {
		UIAlertController *newGifActionSheet = [UIAlertController
			alertControllerWithTitle:@"Create new GIF"
				message:nil
				preferredStyle:
				UIAlertControllerStyleActionSheet];

		UIAlertAction *recordVideo = [UIAlertAction actionWithTitle:@"Record a Video"
			style:UIAlertActionStyleDefault
			handler:^(UIAlertAction * action){
				[self launchCamera];
			}];
}

Method Definition Syntax

#import "RPSTurn.h"

@implementation RPSTurn

-(instancetype)initWithMove:(Move) move{
	self = [super init];
	if (self){
		_move = move;
	}
	return self;
}
#import "RPSGame.h"

@implementation RPSGame

-(instancetype)initWithFirstTurn:(RPSTurn*) playerTurn
	secondTurn: (RPSTurn*)computerTurn {
		self = [super init];

		if(self){
			_firstTurn = playerTurn;
			_secondTurn = computerTurn;
		}
		return self;
	}

The Method throwDown

#import "RPSController.h"
#import "RPSTurn.h"

@implementation RPSController

-(void)throwDown:(Move) playersMove {
	
	// Here the RPSTurn class generates the opponent's move
	RPSTurn *playerTurn = [[RPSTurn alloc]initWithMove:playersMove];
}

Book Class

@interface Book : NSObject

@property (nonatomic) NSString *title;
@property (nonatomic) NSString *author;
@property (nonatomic) int yearOfPublication;

-(instancetype)initWithTitle:(NSString*)title
	author:(NSString*)author
		year:(init)year;

@end

// Book.m
@implementation Book

-(instancetype)initWithTitle:(NSString*)title
			author:(NSString*)author
			year:(int)year {

			self = [super init];
			if(self){
				_title = title;
				_author = author;
				_yearOfPublication = year;
			}
			return self;
}

@end

Weak references for:
1. delegates
2. subviews of the main view

Person.h

@interface Person : NSObject

@property (nonatomic) NSString *name;
@property (nonatomic) NSDate *birthday;

@end

Person.m

// Person.m

@implementation Person

-(instancetype)initWithName:(NSString*)name birthday:(NSDate*)birthday {
	self = [super init];

	if(self){
		_name = name;
		_birthday = birthday;
	}
	return self;
}
@end

Book.h

#import "Person.h"

@interface Book : NSObject

@property (nonatomic) NSString *title;
@property (nonatomic) Person *author;
@property (nonatomic) int yearOfPublication;

-(instancetype)initWithTitle:(NSString*)title
	author:(Person*)author
		year:(int)year;

@end

Custom Initializer

-(instancetype)initWithAddress: (NSMutableString*)address {
	self = [super init];

	if(self){
		_address = [address copy];
		_numberOfBedrooms = 3;
		_hasHotTub = false;	
	}
	return self;
}