Add info bubble to pin and on click directions with Swift - swift2

I'm trying to find out how can i put an info bubble inside the annotation view when i click a pin on a map.
In the view did load I load this code that shows me the map
let latDelta:CLLocationDegrees = 0.01
let longDelta:CLLocationDegrees = 0.01
let evntLat : NSString = venueLat
let evntLng : NSString = venueLng
let latitute1:CLLocationDegrees = evntLat.doubleValue
let longitute2:CLLocationDegrees = evntLng.doubleValue
let theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
let pointLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let region:MKCoordinateRegion = MKCoordinateRegionMake(pointLocation, theSpan)
mappy.setRegion(region, animated: true)
let pinLocation : CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let objectAnnotation = MKPointAnnotation()
objectAnnotation.coordinate = pinLocation
objectAnnotation.title = "\(self.venumeNam)"
self.mappy.addAnnotation(objectAnnotation)
Is there any way to put inside this annotation view a button?
I've tried this
let annotationView = MKAnnotationView()
let detailButton: UIButton = UIButton(type:UIButtonType.DetailDisclosure) as UIButton
annotationView.rightCalloutAccessoryView = detailButton
But i cant figure out how to implement it on my code so it can show it.
Any idea of how can i put this bubble and configure a function when someone clicks it?
FYI it's only one pin that i'm displaying here!
Updated from this answer
class detailsViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mappy: MKMapView!
// Here we add disclosure button inside annotation window
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView{
print(view.annotation!.title) // annotation's title
print(view.annotation!.subtitle) // annotation's subttitle
//Perform a segue here to navigate to another viewcontroller
// On tapping the disclosure button you will get here
}
}
// Here we add disclosure button inside annotation window
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
print("viewForannotation")
if annotation is MKUserLocation {
//return nil
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
//println("Pinview was nil")
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.animatesDrop = true
}
let button = UIButton(type: .DetailDisclosure) as UIButton // button with info sign in it
pinView?.rightCalloutAccessoryView = button
return pinView
}
func displayMarkers() -> Void
{
let latDelta:CLLocationDegrees = 0.01
let longDelta:CLLocationDegrees = 0.01
let evntLat : NSString = venueLat
let evntLng : NSString = venueLng
let latitute1:CLLocationDegrees = evntLat.doubleValue
let longitute2:CLLocationDegrees = evntLng.doubleValue
let theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
let pointLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let annotationView = MKAnnotationView()
let region:MKCoordinateRegion = MKCoordinateRegionMake(pointLocation, theSpan)
mappy.setRegion(region, animated: true)
let pinLocation : CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitute1, longitute2)
let objectAnnotation = MKPointAnnotation()
objectAnnotation.coordinate = pinLocation
objectAnnotation.title = "\(self.venumeNam)"
self.mappy.addAnnotation(objectAnnotation)
}
}

Related

Xcode Swift image zoom gesture

Hope someone can help me. Im trying to make a zoom gesture, so when the image are presented the user can zoom the image with fingers.
My code to present the image are:
// MARK: Show image full screen
func imageTapped(img: AnyObject) {
self.navigationController?.navigationBarHidden = true
let imageView = productImage as UIImageView
let newImageView = UIImageView(image: imageView.image)
newImageView.frame = self.view.frame
newImageView.backgroundColor = .blackColor()
newImageView.contentMode = .ScaleToFill
newImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "dismissFullscreenImage:")
newImageView.addGestureRecognizer(tap)
self.view.addSubview(newImageView)
}
func dismissFullscreenImage(sender: UITapGestureRecognizer) {
sender.view?.removeFromSuperview()
self.navigationController?.navigationBarHidden = false
}
Use UIScrollView and add UIImgeView in scroll view
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate
{
var scrollV : UIScrollView!
var imageView : UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationController?.navigationBarHidden = true
scrollV=UIScrollView()
scrollV.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
scrollV.minimumZoomScale=1
scrollV.maximumZoomScale=3
scrollV.bounces=false
scrollV.delegate=self;
self.view.addSubview(scrollV)
imageView=UIImageView()
imageView.image = UIImage(imageLiteral: "neymar.jpg")
imageView.frame = CGRectMake(0, 0, scrollV.frame.width, scrollV.frame.height)
imageView.backgroundColor = .blackColor()
imageView.contentMode = .ScaleToFill
scrollV.addSubview(imageView)
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
{
return imageView
}
}
Take gesture programmatically and make its method and write down this code in the method.
pinchRecognizerOnView() is my method name. Take one view or image view inside view controller and add this new view in that.Now apply gesture method on this new view.
func pinchRecognizerOnView(sender: UIPinchGestureRecognizer!) {
sender.view?.transform = CGAffineTransformScale((sender.view?.transform)!, sender.scale, sender.scale)
sender.scale = 1
// its for zoom in out screen
}

Why am I getting "EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"

I am getting
"EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)"
in this code
else {
let latitude = NSString(string: places[activePlace]["lat"]!).doubleValue
let longitude = NSString(string: places[activePlace]["lon"]!).doubleValue
let coordinate = CLLocationCoordinate2DMake(latitude, longitude)
let latDelta:CLLocationDegrees = 0.01
let lonDelta:CLLocationDegrees = 0.01
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let region:MKCoordinateRegion = MKCoordinateRegionMake(coordinate, span)
self.Map.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = places[activePlace]["name"]
self.Map.addAnnotation(annotation)
on
let latitude = NSString(string: places[activePlace]["lat"]!).doubleValue
here is my active place variable witch is in a previous table view
var activePlace = -1]
still in the tableview I have this
override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
activePlace = indexPath.row
return indexPath
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "newPlace" {
activePlace = -1
}
in the second view controller ( where I have the problem )
I have this in the view did load
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
if activePlace == -1 {
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
} else {
let latitude = NSString(string: places[activePlace]["lat"]!).doubleValue
let longitude = NSString(string: places[activePlace]["lon"]!).doubleValue
let coordinate = CLLocationCoordinate2DMake(latitude, longitude)
let latDelta:CLLocationDegrees = 0.01
let lonDelta:CLLocationDegrees = 0.01
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let region:MKCoordinateRegion = MKCoordinateRegionMake(coordinate, span)
self.Map.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = places[activePlace]["name"]
self.Map.addAnnotation(annotation)
This code was already there and worked perfect until I added the following code
#IBAction func addCurentLoc(sender: UIBarButtonItem) {
var newCoordinate2 = self.Map.userLocation.location!.coordinate;
var location = CLLocation(latitude: newCoordinate2.latitude, longitude: newCoordinate2.longitude)
title = "new address"
let annotation = MKPointAnnotation();
annotation.title = title;
annotation.coordinate = self.Map.userLocation.location!.coordinate;
CLGeocoder().reverseGeocodeLocation(location) { (placemarks, error) -> Void in
var title = ""
if (error == nil) {
if let p = placemarks?[0] {
var subThouroughfare:String = ""
var thouroughfare:String = ""
if p.subThoroughfare != nil {
subThouroughfare = p.subThoroughfare!
}
if p.thoroughfare != nil {
thouroughfare = p.thoroughfare!
}
title = "\(subThouroughfare) \(thouroughfare)"
}
}
if title == "" {
title = "Added \(NSDate())"
}
places.append(["name":title,"lat":"\(newCoordinate2.latitude)","lon":"\(newCoordinate2.longitude)"])
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate2
annotation.title = title
self.Map.addAnnotation(annotation)
}
self.Map.addAnnotation(annotation);
func mapView(mapView: MKMapView!,
viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!{
if(annotation is MKUserLocation){
return nil;
}
let pinView: Void = mapView.addAnnotation(annotation);
let pinAnnotationView = MKPinAnnotationView(annotation: annotation,reuseIdentifier:"MyIdentifier");
return pinAnnotationView;
}
}
I have been looking for an a solution for a while and can't find out, note that I have checked this answer
EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) on dispatch_semaphore_dispose
as well as this one
what does Error "Thread 1:EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)" mean?
but haven't found the solution, thanks for the help
EDIT: Please note that this question has been modified to be a bit clearer, please ask if you need more info.
Put a breakpoint on the first line of your else then type in lldb:
po places[activePlace] - does it return value or nil?
if returns value type places[activePlace]["lat"]!
One of them will probably return nil, the error you're getting means you're implicitly unwrapping a nil.

MKMapView Not being called Swift ios 8

Hi im just wondering why isnt my MapView function is not being called. I am trying to draw a line between points but all is showing is just the center location.
Thanks in advance.
import UIKit
import CoreLocation
import MapKit
class ThirdViewController: UIViewController , CLLocationManagerDelegate {
#IBOutlet weak var theMap: MKMapView!
#IBOutlet weak var theLabel: UILabel!
var manager:CLLocationManager!
var myLocations: [CLLocation] = []
override func viewDidLoad() {
super.viewDidLoad()
//Setup our Location Manager
manager = CLLocationManager()
self.manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
//Setup our Map View
// theMap.delegate = self
theMap.mapType = MKMapType.Standard
theMap.showsUserLocation = true
}
func locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject]) {
theLabel.text = "\(locations[0])"
myLocations.append(locations[0] as CLLocation)
let spanX = 0.007
let spanY = 0.007
var newRegion = MKCoordinateRegion(center: theMap.userLocation.coordinate, span: MKCoordinateSpanMake(spanX, spanY))
theMap.setRegion(newRegion, animated: true)
println("not yet ")
if (myLocations.count > 1){
println("here ")
var sourceIndex = myLocations.count - 1
var destinationIndex = myLocations.count - 2
let c1 = myLocations[sourceIndex].coordinate
let c2 = myLocations[destinationIndex].coordinate
var a = [c1, c2]
var polyline = MKPolyline(coordinates: &a, count: a.count)
theMap.addOverlay(polyline)
}
}
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
println("sad")
if overlay is MKPolyline {
println("aadsfsad")
var polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blueColor()
polylineRenderer.lineWidth = 4
return polylineRenderer
}
return nil
}
}
in ios8+ MapView didn`t load LocationCoordinate automatically. If we want to use MKMapView to load the more accurate location with "mapView:didUpdateUserLocation":
Premise:
1.setup the mapView delegate.
2.setShowsUserLocation:YES
3.mapView must in a container(addSubview:mapView)!!!!!
For example:
self.mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
_mapView.delegate = self;
[_mapView setShowsUserLocation:YES];
[[UIApplication sharedApplication].keyWindow addSubview:_mapView];

UIKeyboardAnimationDurationUserInfoKey returns extremely small value

func keyboardWillShow(notification:NSNotification){
let userInfo = notification.userInfo
let keyboardFrame = userInfo?[UIKeyboardFrameEndUserInfoKey] as NSValue
let keyboardSize = keyboardFrame.CGRectValue().size
let animationDurationValue = userInfo?[UIKeyboardAnimationDurationUserInfoKey] as NSValue
var animationDuration : NSTimeInterval = 0
animationDurationValue.getValue(&animationDuration)
self.keyboardDelegate?.keyboardWillShowWithSize(keyboardSize, andDuration: animationDuration)
}
In my program, I try to reposition my view when keyboard appears using the function above. With the same way of getting keyboard animation duration in my objective-c code. This one gives me the following status:
duration 5.18065378653631e-315
This is an abnormally small value. Where have I done wrong? Please help!
EDIT: For complete code:
import Foundation
import UIKit
#objc protocol LPKeyboardViewControllerDelegate {
func keyboardWillShowWithSize(size:CGSize, andDuration duration:NSTimeInterval)
func keyboardWillHideWithSize(size:CGSize,andDuration duration:NSTimeInterval)
}
/**
This view controller will move up its view when a keyboard appears in its view
*/
class LPKeyboardViewController: UIViewController {
var keyboardDelegate: LPKeyboardViewControllerDelegate?
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
println("Start listening to keyboard")
}
func keyboardWillShow(notification:NSNotification){
let userInfo = notification.userInfo
let keyboardFrame = userInfo?[UIKeyboardFrameEndUserInfoKey] as NSValue
let keyboardSize = keyboardFrame.CGRectValue().size
let animationDurationValue = userInfo?[UIKeyboardAnimationDurationUserInfoKey] as NSValue
var animationDuration : NSTimeInterval = 0
animationDurationValue.getValue(&animationDuration)
self.keyboardDelegate?.keyboardWillShowWithSize(keyboardSize, andDuration: animationDuration)
}
func keyboardWillHide(notification:NSNotification){
let userInfo = notification.userInfo
let keyboardFrame = userInfo?[UIKeyboardFrameEndUserInfoKey] as NSValue
let keyboardSize = keyboardFrame.CGRectValue().size
let animationDurationValue = userInfo?[UIKeyboardAnimationDurationUserInfoKey] as NSNumber
var animationDuration : NSTimeInterval = animationDurationValue.doubleValue
self.keyboardDelegate?.keyboardWillHideWithSize(keyboardSize, andDuration: animationDuration)
}
}
The docs state that the object for this key is an NSNumber so you don't have to jump through the hoops you are you can just do
let animationDurationValue = userInfo?[UIKeyboardAnimationDurationUserInfoKey] as NSNumber
let animationDuration = animationDurationValue.doubleValue

Adding IBOutlets to Other Class Files in Swift?

I'm trying to build an application in Swift for OS X (With Xcode 6.1 GM) that is a MenuBar agent with a single window for preferences.
Though I've been able to get most of my menubar functionality working, it all exists in the AppDelegate and looks pretty messy.
import Cocoa
import AppKit
import Foundation
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var downloadClass = DownloadController()
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var downloadButton: NSButton!
#IBOutlet weak var subredditField: NSTextField!
#IBOutlet weak var nsfwMarked: NSButton!
#IBOutlet weak var sortFilter: NSPopUpButton!
var statusBar = NSStatusBar.systemStatusBar()
var statusBarItem : NSStatusItem = NSStatusItem()
var menu: NSMenu = NSMenu()
var subSort: NSMenu = NSMenu()
override func awakeFromNib() {
//Add statusBarItem
statusBarItem = statusBar.statusItemWithLength(-1)
statusBarItem.menu = menu
let icon = NSImage(named: "arrow16black")
statusBarItem.image = icon
var downloadItem: NSMenuItem = NSMenuItem()
downloadItem.title = "Download"
downloadItem.action = Selector("downloadPressed:")
downloadItem.keyEquivalent = ""
menu.addItem(downloadItem)
var menuItem: NSMenuItem = NSMenuItem()
menuItem.title = "Preferences..."
//Open view on button click
menuItem.action = Selector("setWindowVisible:")
menuItem.keyEquivalent = ""
menu.addItem(menuItem)
//define sorting filters
let sortOptions = NSArray(array: ["Hot","New","Top","Rising","Controversial"])
sortFilter.addItemsWithTitles(sortOptions)
var sortItem: NSMenuItem = NSMenuItem()
sortItem.title = "Sort By"
menu.addItem(sortItem)
//Add sort options as submenu
for sort in sortOptions {
var item: NSMenuItem = NSMenuItem()
item.title = sort as String
item.keyEquivalent = ""
item.action = Selector("setActiveSort:")
subSort.addItem(item)
}
menu.setSubmenu(subSort, forItem: sortItem)
//Test receiving menu
let userDefaults = NSUserDefaults.standardUserDefaults()
if let filterDefault : AnyObject = userDefaults.objectForKey("filter") {
var active : NSString = filterDefault as NSString
sortFilter.selectItemWithTitle(active)
println(active)
subSort.itemWithTitle(active)?.state = 1
}
}
func setActiveSort(sender: NSMenuItem) {
//Turn off all other active filters
let allSorts = subSort.itemArray
var a = 0
while a < subSort.numberOfItems {
var filter = subSort.itemAtIndex(a)
filter?.state = 0
a++
}
//Make selected filter active and store value in Defaults
sender.state = 1
sortFilter.selectItemWithTitle(sender.title)
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(sender.title, forKey: "filter")
}
#IBAction func downloadPressed(sender: AnyObject) {
let subreddit: NSString = NSString(string: subredditField.stringValue)
let sortBy: NSString = NSString(string: sortFilter.titleOfSelectedItem!)
var sort = sortBy.lowercaseString
let nsfw: Bool = Bool(nsfwMarked.integerValue)
downloadClass.startController(subreddit, sortBy: sort, markNSFW: nsfw)
}
func setWindowVisible(sender: AnyObject) {
self.window!.orderFront(self)
}
func applicationDidFinishLaunching(aNotification: NSNotification?) {
// Insert code here to initialize your application
//Don't display application window at launch
self.window!.orderOut(self)
//On launch, get user preferences if set
let userDefaults = NSUserDefaults.standardUserDefaults()
if let nsfwMarkedPref : AnyObject = userDefaults.objectForKey("NSFW?") {
//Set nsfw state to stored value
nsfwMarked.state = (nsfwMarkedPref.integerValue == 1) ? NSOnState : NSOffState;
}
if let storedSubreddit : AnyObject = userDefaults.objectForKey("subreddit") {
//set subreddit string to stored value
subredditField.stringValue = storedSubreddit as String
}
//Get screen resolution
let ms = NSScreen.mainScreen()
let frame = ms?.frame
println(frame!.size.width)
}
func applicationWillTerminate(aNotification: NSNotification?) {
// Insert code here to tear down your application
//Set the user preferences on exit.. this should be moved to onButtonState
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(nsfwMarked.integerValue, forKey: "NSFW?")
let subreddit: NSString = NSString(string: subredditField.stringValue)
userDefaults.setObject(subreddit, forKey: "subreddit")
}
}
Currently, the IBAction of the downloadButton in my view will call the function within the DownloadController. But ideally I would like to be able to have the IBAction of downloadPressed right within the DownloadController.swift file, but I cannot seem to figure out how to go about this..
Thanks!
Create a XIB file or use storyboard and set it's file owner as your UI view controller. Then setup your actions and outlets there. I would recommend you watch some videos on you tube before you proceed.

Resources