UILocalNotificaiton gets called twice in one post.
Does anybody know the reason?
I found it in iOS9.1. But in iOS8.0 it works normally.
Below is my code:
extension UILocalNotification {
class func postNotification(message : String!, soundName : String?) {
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let localNotification : UILocalNotification = UILocalNotification()
localNotification.fireDate = NSDate().dateByAddingTimeInterval(1)
localNotification.timeZone = NSTimeZone.defaultTimeZone()
localNotification.alertBody = message
localNotification.repeatInterval = NSCalendarUnit(rawValue: 0)
if soundName != nil {
localNotification.soundName = soundName
} else {
localNotification.soundName = UILocalNotificationDefaultSoundName
}
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
}
}
}
Related
Need help in figuring out why my function is not executing when I thought it should but it executed after the completion block in the code. I am fairly new to Xcode so please excuse me if things sound confusing here. Below is my code.
class ImageDownloader{
typealias completionHandler = (Result<Set<ARReferenceImage>, Error>) -> ()
typealias ImageData = (image: UIImage, orientation: CGImagePropertyOrientation, physicalWidth: CGFloat, name: String)
static let URLDic = [ReferenceImagePayload]()
class func getDocumentData(completion:#escaping ([ReferenceImagePayload]) -> ()) {
var documentCollection: [ReferenceImagePayload] = []
db.collection("Users").getDocuments {(snapshot, error) in
if error == nil && snapshot != nil {
var index = 0
for document in snapshot!.documents {
let loadData = document.data()
index += 1
if loadData["Target URL"] != nil {
let url = loadData["Target URL"]
let urlString = URL(string: "\(String(describing: url ?? ""))")
let urlName = loadData["Target Image"]
documentCollection.append(ReferenceImagePayload(name: urlName as! String, url: urlString!))
if snapshot!.documents.count == index {
// After finished, send back the loaded data
completion(documentCollection)
}
}
}
}
}
}
static var receivedImageData = [ImageData]()
class func downloadImagesFromPaths(_ completion: #escaping completionHandler) {
// THE LINE BELOW WHERE I CALL THE FUNCTION IS NOT EXECUTED WHEN THIS CLASS IS INITIALLY CALLED. BUT AS THE CODE RUNS, THIS LINE BELOW IS EXECUTED AFTER THE COMPLETIONOPERATION = BLOCKOPERATION IS COMPLETED.
let loadedDataDic: () = getDocumentData { (URLDic) in
print(URLDic.self, "Got it")
}
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 6
let completionOperation = BlockOperation {
OperationQueue.main.addOperation({
completion(.success(referenceImageFrom(receivedImageData)))
// LINE "let loadedDataDic: () = getDocumentData" ONLY GOT EXECUTED AT THIS POINT
})
}
URLDic.forEach { (loadData) in
let urlstring = loadData.url
let operation = BlockOperation(block: {
do{
let imageData = try Data(contentsOf: loadData.url)
print(imageData, "Image Data")
if let image = UIImage(data: imageData){
receivedImageData.append(ImageData(image, .up, 0.1, loadData.name))
}
}catch{
completion(.failure(error))
}
})
completionOperation.addDependency(operation)
}
operationQueue.addOperations(completionOperation.dependencies, waitUntilFinished: false)
operationQueue.addOperation(completionOperation)
}
}
I am trying to run a shell command when Logout Event occurs in Mac
logoutNotificationCenter.notificationCenter.addObserver(self, selector: #selector(AppDelegate.logOut),name:NSWorkspace.willPowerOffNotification, object: nil)
inside logout I am using to run a shell command
func shell(path:String,commandargs: [String]) -> Bool
{
var ret : Bool = false
let task = Process()
task.launchPath = path
task.arguments = commandargs
task.launch()
task.waitUntilExit()
if !task.isRunning {
let status = task.terminationStatus
if status == 0 {
ret = true
} else {
ret = false
}
}
return ret
}
Though my notification is triggered by shell is not being run , even before that my system is shutting down. Is there a way I can halt logout until my shell command is executed.
I read your question again and the problem is that the applicationShouldTerminate(_:) is called before the NSWorkspace.willPowerOffNotification is sent. Which means that you don't know what's going on.
Then I realized that we've got the kAEQuitReason. Was curious if it still works and it does. Example below. Modify it in a way that fits your needs.
import Cocoa
#main
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet var window: NSWindow!
private var logoutTaskLaunched = false
private func launchLogoutTask() {
assert(!logoutTaskLaunched, "Logout task was already launched")
let task = Process()
task.executableURL = URL(fileURLWithPath: "/bin/sleep")
task.arguments = ["5"]
task.terminationHandler = { task in
if task.terminationStatus == 0 {
print("Logout task - success")
DispatchQueue.main.async {
NSApp.reply(toApplicationShouldTerminate: true)
}
} else {
print("Logout task - failed")
DispatchQueue.main.async { [weak self] in
NSApp.reply(toApplicationShouldTerminate: false)
self?.logoutTaskLaunched = false
}
}
}
do {
try task.run()
logoutTaskLaunched = true
print("Logout task - Sleeping for 5s")
}
catch {
print("Logout task - failed to launch task: \(error)")
NSApp.reply(toApplicationShouldTerminate: false)
}
}
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
let reason = NSAppleEventManager.shared()
.currentAppleEvent?
.attributeDescriptor(forKeyword: kAEQuitReason)
switch reason?.enumCodeValue {
case kAELogOut, kAEReallyLogOut:
print("Logout")
if !logoutTaskLaunched {
launchLogoutTask()
}
return .terminateLater
case kAERestart, kAEShowRestartDialog:
print("Restart")
return .terminateNow
case kAEShutDown, kAEShowShutdownDialog:
print("Shutdown")
return .terminateNow
case 0:
// `enumCodeValue` docs:
//
// The contents of the descriptor, as an enumeration type,
// or 0 if an error occurs.
print("We don't know")
return .terminateNow
default:
print("Cmd-Q, Quit menu item, ...")
return .terminateNow
}
}
}
Hi I am trying to add UIPanGestureRecognizer to UIImageView (in my case, it's an emoji). All other UIGestureRecognizers such as long press, rotation, and pinch work well. However, it gives me an error: unrecognized selector sent to instance when I add UIPanGestureRecognizer. I've spent a day trying to figure out the reason but failed to fix it. Please help! Thanks in advance.
This is a function where I added UIGestureRecognizer to sticker
func emojiInsert(imageName: String) {
deleteButtonHides()
let stickerView: UIImageView = UIImageView(frame: CGRectMake(backgroundImage.frame.width/2 - 50, backgroundImage.frame.height/2 - 50, stickerSize, stickerSize))
stickerView.image = UIImage(named: imageName)
stickerView.userInteractionEnabled = true
stickerView.accessibilityIdentifier = "sticker"
let deleteStickerButton: UIImageView = UIImageView(frame: CGRectMake(stickerView.frame.width - 5 - stickerView.frame.width/3, 5, stickerView.frame.width/3, stickerView.frame.height/3))
deleteStickerButton.image = UIImage(named: "button_back")
deleteStickerButton.accessibilityIdentifier = "delete"
deleteStickerButton.userInteractionEnabled = true
deleteStickerButton.alpha = 0
deleteStickerButton.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "deleteButtonTouches:"))
stickerView.addSubview(deleteStickerButton)
stickerView.addGestureRecognizer(UIPinchGestureRecognizer(target: self, action: "handlePinch:"))
stickerView.addGestureRecognizer(UIRotationGestureRecognizer(target: self, action: "handleRotate:"))
stickerView.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: "handleLongPress:"))
stickerView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePan"))
print("emojiInsert : \(imageName)")
backgroundImage.addSubview(stickerView)
}
Below are call back functions I added in the end of the view.swift. I used touchesbegan and touchesMoved to drag an emoji but emoji moved in weird way after rotation. So now I am trying to use UIPanGesture to drag an emoji.
#IBAction func handlePinch(recognizer : UIPinchGestureRecognizer) {
if(deleteMode) {
return
}
print("handlePinch \(recognizer.scale)")
if let view = recognizer.view {
view.transform = CGAffineTransformScale(view.transform,
recognizer.scale, recognizer.scale)
recognizer.scale = 1
}
}
#IBAction func handleRotate(recognizer : UIRotationGestureRecognizer) {
if(deleteMode) {
return
}
if let view = recognizer.view {
view.transform = CGAffineTransformRotate(view.transform, recognizer.rotation)
recognizer.rotation = 0
}
}
#IBAction func handlePan(recognizer:UIPanGestureRecognizer) {
if(deleteMode) {
return
}
let translation = recognizer.translationInView(self.view)
if let view = recognizer.view {
view.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPointZero, inView: self.view)
}
#IBAction func handleLongPress(recognizer: UILongPressGestureRecognizer) {
if(recognizer.state == UIGestureRecognizerState.Began) {
if(!deleteMode) {
print("LongPress - Delete Shows")
for (_, stickers) in self.backgroundImage.subviews.enumerate() {
for (_, deleteButtons) in stickers.subviews.enumerate() {
if let delete:UIImageView = deleteButtons as? UIImageView{
if(delete.accessibilityIdentifier == "delete") {
delete.alpha = 1
}
}
}
}
deleteMode = true
} else {
deleteButtonHides()
}
}
}
Again, please help! Thanks in advance.
The problem is that you're missing a colon. In the following line:
stickerView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: "handlePan"))
The handlePan should be handlePan:. That's because the Objective-C signature for your method is:
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
The colon is part of the method name.
My app works perfectly fine with iOS 8 but yesterday I upgraded to iOS 9 and Xcode 7 then my app crashes. The error message is cannot invoke 'dataTaskwithURL' with an argument list of type '(NSURL, (_, ,)throws -> Void)'. I googled it and found a similar question here but the solution didn't really work (the solution was to add the do/catch blocks around the code). Can anyone help me with mine problem? Thank you!!!
Here's my code
import UIKit
import Foundation
import CoreLocation
class GoogleDataProvider {
let apiKey = "AIzaSyCQo-clIkek87N99RVh2lmFX9Mu9QPhAtA"
let serverKey = "AIzaSyBzmv7wPFcPAe1ucy5o6dqaXnda9i9MqjE"
var photoCache = [String:UIImage]()
var placesTask = NSURLSessionDataTask()
var session: NSURLSession {
return NSURLSession.sharedSession()
}
func fetchPlacesNearCoordinate(coordinate: CLLocationCoordinate2D, radius:Double, types:[String],keyword:String, completion: (([GooglePlace]) -> Void)) -> ()
{
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?key=\(serverKey)&location=\(coordinate.latitude),\(coordinate.longitude)&radius=\(radius)&keyword=\(keyword)&rankby=prominence&sensor=true"
let typesString = types.count > 0 ? types.joinWithSeparator("|") : "food"
urlString += "&types=\(typesString)"
urlString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
if placesTask.taskIdentifier > 0 && placesTask.state == .Running {
placesTask.cancel()
}
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
do{
//******************Here's the line that displays error
placesTask = session.dataTaskWithURL(NSURL(string: urlString)!) {
(data, response, error) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
var placesArray = [GooglePlace]()
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as? NSDictionary {
if let results = json["results"] as? NSArray {
for rawPlace:AnyObject in results {
let place = GooglePlace(dictionary: rawPlace as! NSDictionary, acceptedTypes: types)
placesArray.append(place)
if let reference = place.photoReference {
self.fetchPhotoFromReference(reference) { image in
place.photo = image
}
}
}
}
}
dispatch_async(dispatch_get_main_queue()) {
completion(placesArray)
}
}
}catch{
}
placesTask.resume()
}
func fetchDirectionsFrom(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D, completion: ((String?) -> Void)) -> ()
{
let urlString = "https://maps.googleapis.com/maps/api/directions/json?key=\(serverKey)&origin=\(from.latitude),\(from.longitude)&destination=\(to.latitude),\(to.longitude)&mode=walking"
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
do{
//******************************Here too ****************************
session.dataTaskWithURL(NSURL(string: urlString)!) {
(data, response, error) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
var encodedRoute: String?
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as? [String:AnyObject] {
if let routes = json["routes"] as AnyObject? as? [AnyObject] {
if let route = routes.first as? [String : AnyObject] {
if let polyline = route["overview_polyline"] as AnyObject? as? [String : String] {
if let points = polyline["points"] as AnyObject? as? String {
encodedRoute = points
}
}
}
}
}
dispatch_async(dispatch_get_main_queue()) {
completion(encodedRoute)
}
}.resume()
}catch{
}
}
}
Sorry this is my first time posting the code style is a little bit confusing sorry about the indentation mess :)
Thanks again!!!
dataTaskWithURL:completionHandler: does not throw error.
Put do and catch inside dataTaskWithURL method.
for example:
session.dataTaskWithURL(NSURL(string: urlString)!) {
(data, response, error) -> Void in
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
var encodedRoute: String?
do {
if let json = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as? [String:AnyObject] {
if let routes = json["routes"] as AnyObject? as? [AnyObject] {
if let route = routes.first as? [String : AnyObject] {
if let polyline = route["overview_polyline"] as AnyObject? as? [String : String] {
if let points = polyline["points"] as AnyObject? as? String {
encodedRoute = points
}
}
}
}
}
} catch {
}
dispatch_async(dispatch_get_main_queue()) {
completion(encodedRoute)
}
}.resume()
I am setting up an iOS 8 app to request Heath Kit Store authorization to share types. The request Read/Write screen shows fine and on selecting Done, I see the completion callback immediately after. In this callback, I am pushing a new view controller. I set a breakpoint for the code that is programmatically pushing the next view controller and this is called immediately, but the transition doesn't occur until about 10 seconds later.
Some code:
#IBAction func enable(sender: AnyObject) {
let hkManager = HealthKitManager()
hkManager.setupHealthStoreIfPossible { (success, error) -> Void in
if let error = error {
println("error = \(error)")
} else {
println("enable HK success = \(success)")
self.nextStep()
}
}
}
func nextStep() {
self.nav!.pushViewController(nextController, animated: true)
}
class HealthKitManager: NSObject {
let healthStore: HKHealthStore!
override init() {
super.init()
healthStore = HKHealthStore()
}
class func isHealthKitAvailable() -> Bool {
return HKHealthStore.isHealthDataAvailable()
}
func setupHealthStoreIfPossible(completion: ((Bool, NSError!) -> Void)!) {
if HealthKitManager.isHealthKitAvailable()
{
healthStore.requestAuthorizationToShareTypes(dataTypesToWrite(), readTypes: dataTypesToRead(), completion: { (success, error) -> Void in
completion(success, error)
})
}
}
func dataTypesToWrite() -> NSSet {
let runningType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
let stepType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
return NSSet(objects: runningType, stepType)
}
func dataTypesToRead() -> NSSet {
let runningType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)
let stepType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)
let climbedType = HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierFlightsClimbed)
return NSSet(objects: runningType, stepType, climbedType)
}
}
Any thoughts on what is causing the time delay for the transition?
The problem was that the completion block is returned in the background queue. I just put the transition call back onto the main queue as follows:
hkManager.setupHealthStoreIfPossible { (success, error) -> Void in
if let error = error {
println("error = \(error)")
} else {
dispatch_async(dispatch_get_main_queue(), {
println("enable HK success = \(success)")
self.nextStep()
});
}
}
}