LLDB and Breakpoint Actions

override func motionEnded(motion: UIEventSubtype,
	withEvent event: UIEvent){
		if motion == .MotionShake
		{
			disperseBugsAnimation()
		}
	}
	func handleSignleTap(recognizer:
		UITapGestureRecognizer){
		addBugToView()
		addButToView()
		}

thread backtrace all

Apple’s LLDB Quick Start Guide
https://developer.apple.com/library/content/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-command-examples.html#//apple_ref/doc/uid/TP40012917-CH3-SW1

The Debug Bar

func addBugToView(){
if bugs.count < maxBugs { let newBug = bugFactory.createBug() bug.append(newBug) moveBugsAnimation() } } func emptyBugsFromView(){ for bug in self.bugs { bug.removeFromSuperview() } self.bugs.removeAll(keepCapacity: true) } [/code] Getting Help with Bugs Stack Overflow
-be specific as possible
-provides steps leading to the problems
– can use text, code, images, gifts…

No More Crash!

Pay attention to any information provided when the application crashes!

@IBAction func dismissSettingsTouched(sender:
	AnyObject){
		self.dismissViewControllerAnimated(true, completion: nil)
	}

@IBAction func bugTypeSelected(sender: UIButton){
	bugFactory.currentBugType = BugFactory.BugType
	(rawValue: sender.currentTitle!.toInt()!)!
	self.dismissViewControllerAnimated(true, completion: nil)
}
println("starting bug work")
for bug in bugs {
	println("done with \(bug)")
}
println("ending bug work")
let log = XCGLogger()
log.setup(logLevel: .Debug, showLineNumbers: true)
log.debug("starting bug work")
for bug in bugs {
	log.verbose("done with \(bug)")
}
log.debug("ending bug work")
import UIKit
class BreakpointBugViewController: UIViewController {
	// MARK: Properties

	let bugFactory = BugFactory.sharedInstance()
	let maxBugs = 0
	let moveDuration = 3.0
	let disperseDuration = 1.0

	var bugs = [UIImageView]()
}
extension BreakpointBugViewController {
	override func canBecomeFirstResponder() ->
		Bool { return true }
	override func motionEnded(motion: UIEventSubtype, withEvent evnt: UIEvent)
	{
		if motion == .MotionShake {
			disperseBugsAnimation()
		}
	}
	func handleSingleTap(recognizer:
		UITapGestureRecognizer){
		addBugToView()
		addBugToView()
		}
}

Warnings and Errors

warnings – issues identified by the compiler that MIGHT CAUSE PROBLEMS or have UNINTENDED SIDE-EFFECTS on running application
errors – issues identified by the compiler that MUST BE FIXED prior to running application

logic error:a bug in a program that causes it to operate incorrectly, but not to terminate abnormally
runtime errors: issues that occur while your application is running – these can be logic errors or errors that cause application to crash
software bug: an error, flaw, failure, or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways
static errors: issues identified by the compiler that must be fixed prior to running application
warning: issues that might cause problems or have unintended side-effects on running application

Reproduce the problem -> Gather debug information -> what is the value of a variable? what kind of error?
logs, program state, …

=> Form a Hypothesis

print debugging
-only use print statements to debug

extension PrintBugViewController {
	override func canBecomeFirstResponder() -> Bool {
		return true
	}
	override func motionEnded(motion: UIEventSubtype,
	withEvent event: UIEvent){
		if motion == .MotionShake {
			disperseBugsAnimation()
		}
	}
	func handleSingTap(recognizer: UITapGestureRecognizer) {
		addBugToView()
	}
}

func addBugToView(){
println(self)
if bugs.count < maxBugs { let newBug = bugFactory.createBug() bugs.append(newBug) view.addSubview(newBug) moveBugsAnimation() } println(self) } func emptyBugsFormView(){ for bug in self.bugs { bug.removeFromSuperview() } } extension PrintBugViewController : Printable, DebugPrintable { override var description: String { return "PrintBugViewController contains \(bugs.count) bugs\n" } }[/code]

Debugging, Printing, and Logging

FinalBugViewController.swift

import UIKit

// MARK: - FinalBugViewController: UIViewController

class FinalBugViewController: UIViewController {

    // MARK: Properties
    
    let bugFactory = BugFactory.sharedInstance()
    let maxBugs = 100
    let moveDuration = 3.0
    let disperseDuration = 1.0    
    var bugs = [UIImageView]()

    // MARK: Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()        
        let singleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap))
        view.addGestureRecognizer(singleTapRecognizer)                
    }

    // MARK: Bug Functions
    
    func addBugToView() {
        if bugs.count < maxBugs {
            let newBug = bugFactory.createBug()
            bugs.append(newBug)
            view.addSubview(newBug)
            moveBugsAnimation()
        }
    }

    func emptyBugsFromView() {
        for bug in self.bugs {
            bug.removeFromSuperview()
        }
        self.bugs.removeAll(keepCapacity: true)
    }
    
    // MARK: View Animations
    
    func moveBugsAnimation() {
        UIView.animateWithDuration(moveDuration) {
            for bug in self.bugs {
                let randomPosition = CGPoint(x: CGFloat(arc4random_uniform(UInt32(UInt(self.view.bounds.maxX - bug.frame.size.width))) + UInt32(bug.frame.size.width/2)), y: CGFloat(arc4random_uniform(UInt32(UInt(self.view.bounds.maxY - bug.frame.size.height))) + UInt32(bug.frame.size.height/2)))
                bug.frame = CGRect(x: randomPosition.x - bug.frame.size.width/1.5, y: randomPosition.y - bug.frame.size.height/1.5, width: BugFactory.bugSize.width, height: BugFactory.bugSize.height)
            }
        }
    }
    
    func disperseBugsAnimation() {
        UIView.animateWithDuration(disperseDuration, animations: { () -> Void in
            for bug in self.bugs {
                let offScreenPosition = CGPoint(x: (bug.center.x - self.view.center.x) * 20, y: (bug.center.y - self.view.center.y) * 20)
                bug.frame = CGRect(x: offScreenPosition.x, y: offScreenPosition.y, width: BugFactory.bugSize.width, height: BugFactory.bugSize.height)
            }
        }, completion: { (finished) -> Void in
            if finished { self.emptyBugsFromView() }
        })
    }
    
    // MARK: Actions
    
    @IBAction func popToMasterView() {
        self.navigationController!.popToRootViewControllerAnimated(true)
    }
}

// MARK: - FinalBugViewController (UIResponder)

extension FinalBugViewController {
    override func canBecomeFirstResponder() -> Bool { return true }
    override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) {
        if motion == .MotionShake { disperseBugsAnimation() }
    }
    func handleSingleTap(recognizer: UITapGestureRecognizer) { addBugToView() }
}

// MARK: - FinalBugViewController (CustomStringConvertible)

// NOTE: You don't have to conform to CustomStringConvertible since this is already done by FinalBugViewController's superclasses (via NSObject).

extension FinalBugViewController {

    override var description: String {
        return "FinalBugViewController contains \(bugs.count) bugs\n"
    }
    
}

// MARK: - FinalBugViewController (CustomDebugStringConvertible)

// NOTE: You don't have to conform to CustomDebugStringConvertible since this is already done by FinalBugViewController's superclasses (via NSObject).

extension FinalBugViewController {
    
    override var debugDescription: String {
        var index = 0
        var debugString = "FinalBugViewController contains \(bugs.count) bugs...\n"
        for bug in bugs {
            debugString = debugString + "Bug\(index): \(bug.frame)\n"
            index += 1
        }
        return debugString
    }
}

// MARK: - FinalBugViewController (debugQuickLookObject)

extension FinalBugViewController {
    
    func debugQuickLookObject() -> AnyObject? {
        
        let singleSquareLength: CGFloat = 10.0
        let squaresInRow = 10
        let imageSize = CGSizeMake(singleSquareLength * CGFloat(squaresInRow), singleSquareLength * CGFloat(bugs.count / squaresInRow + 1))
        
        UIGraphicsBeginImageContextWithOptions(imageSize, true, 0)
        var x: CGFloat = 0.0
        var y: CGFloat = 0.0
        for bug in bugs {
            bug.tintColor.set()
            UIRectFill(CGRectMake(x, y, singleSquareLength, singleSquareLength))
            x += singleSquareLength
            if x > CGFloat(squaresInRow) * singleSquareLength {
                y += singleSquareLength
                x = 0.0
            }
        }
        UIColor.yellowColor().set()
        UIRectFill(CGRectMake(x, y, singleSquareLength, singleSquareLength))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return image
    }
}
import UIKit

// MARK: - FinalSettingsViewController: UIViewController

class FinalSettingsViewController: UIViewController {
    
    // MARK: Properties
    
    let bugFactory = BugFactory.sharedInstance()
    
    // MARK: Outlets
    
    @IBOutlet weak var currentBugTypeImageView: UIImageView!
    
    // MARK: Life Cycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        currentBugTypeImageView.tintColor = BugFactory.bugTints[bugFactory.currentBugType.rawValue]
    }
    
    // MARK: Actions
    
    @IBAction func dismissSettingsTouched(sender: AnyObject) { self.dismissViewControllerAnimated(true, completion: nil) }
    
    @IBAction func bugTypeSelected(sender: UIButton) {
        bugFactory.currentBugType = BugFactory.BugType(rawValue: Int(sender.currentTitle!)!)!
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}

Geofencing

GoogleAPIClient, GeoFence(Latitude, Longitude, Radius, Expiration)
ArrayList -> GeoFencingRequest (addGeoFences)

create a new App in Android Studio
add the services libraries to buildgradle
edit App.manifest to use the service libraries

edit layout.xml file
add an onClick Handler to this button
call it ‘addGeofencesButtonHandler’

create a GeoFenceTransitionsIntentService class extends IntentService
Add constructor and onCreate() overrides
create onHandleIntent override take Intent as parameter, return void

onHandleIntent(Intent intent) method
Get geofence data from the intent
check for Errors!

onHandleIntent(Intent intent) method
Get the transition type
1. for Enter
2. for Exit

List<Geofence> triggeringGeofences = geofencingEvent

write a sendNotification helper method it should take a string and send a notification with that string

public final class Constant {
	private Constants(){
	}
}

public static final HashMap<String, LatLng> BAY_AREA_LANDMARKS =
	new HashMap<String, LatLng();>
		static {}
private GeofencingRequest getGeofencingRequest(){
}

private PendingIntent getGeofencePendingIntent(){
	Intent intent = new Intent();
	return PendingIntent.getService();
}

Building onReceive()

Received a Context and an Intent
ArrayList
getParcelableArrayListExtra()
Iterate throught ArrayList
– getType() -DetectedActivity code
– getConfidence()

Setting up the Client
onStart()/ onStop()
onPause()
Get LocalBroadcastManager and Unregister our receiver
onResume()
Get LocalBroadcastManager and register our receiver
Use same IntentFilter name(BROADCAST_ACTION)

@Override
protected void onStart(){
	super.onStart();
	mGoogleApiClient.connect();
}

@Override
protected void onStop(){
	super.onStop();
	mGoogleApiClient.disconnect();
}

Implementing Buttons
requestActivityUpdatesButtonHandler
.requestActivityUpdates()
The API Client, Interval in ms
A Pending Intent – getActivityDetectionPendingIntent()
removeActivityUpdatesHandler
.removeActivityUpdates()
API Client & Pending Intent

Asynchronous Stuff

Using IntentService

Activity: StartService
onHandleIntent IntentService

package lmoroney.com.hogeactivity;

import android.app.IntentService;

public class DetectedActivitiesIntentService {
	protected statid final String TAG = "detection_is";
	public DetectedActivitiesIntentService(){
		// Use the TAG to name the worker thread.
		super(TAG);
	}
}

Get ActivityRecognitionResult
Use .getProbableActivities() to get Array
create a new Intent to send results
Add activities to Intent
Use a LocalBroadcastManager

Editing the Main Activity
on the class declaration
implement onConnectionCallbacks
and onConnectionFailedLsitener
Within the Class
Implement onConnected
Implement onConnectionSuspended
Implement onConnectionFailed

public class MainActivity extends ActionBarActivity
	implements GoogleApiClient.ConnectionCallbacks,
	GoogleApiClient.OnConnectionFailedListener {

	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	@Override
	public void onConnected(Bundle connectionHint){	
	}

	@Override
	public void onConnectionFailed(ConnectionResult result){
	}
}

The Receiver Class
class that extends BroadcastReceiver
works best as a nested class on MainActivity
Create ActivityDetectionBroadcastReciever
– make it nested
– extends BroadcastReceiver
– Override onReceive(Context, Intent

public class ActivityDetectionBroadcastReceiver extends BroadcastReceiver {
	protected static final String TAG = "receiver";

	public void onReceiver(Context context, Intent intent){
	
	}
}

Going deeper with location

Steps
1. specify using Google Services
2. Access fine location

To have connection callbacks
– implements ConnectionCallbacks, OnConnectionFailedListener

@Override
public void onConnected(Bundle bundle){
	super.onStart();
	mGoogleApiClient.connect();
}
@Override
protected void onStop(){
	super.onStop();
	if(mGoogleApiClient.isConnected()) {
		mGoogleApiClient.disconnected();
	}
}
@Override
protected void onConnected(Bundle connectionHint){
	mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
	if(mLastLocation!=null){
	 mLatitudeText.setText(String.valueOf(mLastLocation.getLatitude()));
	 mLongitudeText.setText(String.valueOf(mLastLocation.getLongitude()));
	}
}

Setting up
-create App
-edit the Layout
-Add String.xml
-Update Build.gradle and AnxdroidManifest.xml

Different Priority Values

setInterval(period);
mil second

PRIORITY_BALANCED_POWER_ACCURACY
PRIORITY_HIGH_ACCURACY
PRIORUTY_LOW_POWER
PRIORITY_NO_POWER

steps to use Location Services
1. create a GoogleApiClient
that uses the Location Services API
2. Extend activity with the GoogleApiClientConnectionCallbacks
callbacks
3. Extend activity with the GoogleApiClient.OnConnectionFailedListener
Listener in case the connection fails
4. Extend activity with the LocationListener
listener for lacation updates
5. After connecting the GoogleApiClient
wait for the onConnected
callback
6. In this callback, set up onLocationChanged
callback, and in this can capture location information