Swift how to send eMail mail in AppDelegate fetch?












0














Im totally helpless right now, i'm trying to send an eMail for data upload in an iOS Swift 4 App. I found the Obj-C Mailcore library which works in normal code, for example in a button press callback. But if i'm trying to use the same code in my AppDelegate fetch func it doesn't return from the completionHandler.



The Mailcore send operation is async so i used a semaphore wrapper around it, but the completion handler is never called.



Edit:



Apparently the code does not work in the button with the Semaphore. Only if i remove the



let _ = semaphore.wait(timeout: DispatchTime.distantFuture)


part.



So is there another way to wait for the completion of the async completionBlock?




Yes, look at my answer :-)



My code:



let smtpSession = MCOSMTPSession()
[...]
let sendOperation = smtpSession.sendOperation(with: rfc822Data!)
[...]
let semaphore = DispatchSemaphore(value: 0)
if (sendOperation != nil) {
print("Starting sendOperation...")
sendOperation?.start { (error) -> Void in
if (error != nil) {
sendingError = true
print("Error sending email: (error)")
} else {
print("Successfully sent email!")
}
sendingDone = true
semaphore.signal()
}
let _ = semaphore.wait(timeout: DispatchTime.distantFuture)
} else {
print("Cant init sendOperation")
sendingError = true
}









share|improve this question
























  • Are you sure sendOperation is not-nil when you call start ? Theres nothing special about an object that adopts UIApplicationDelegate
    – Warren Burton
    Nov 23 '18 at 12:23










  • @Warren Burton Im not sure, but i just copy and pasted it from the button code where it worked so i doesnt bothered. I will check this but shouldnt it crash if i call start() on a nil object?
    – skilled-solutions
    Nov 23 '18 at 12:25










  • sendOperation appears to be Optional from your code. You can see that from sendOperation? using optional chaining.
    – Warren Burton
    Nov 23 '18 at 12:41












  • @Warren Burton Now i see what you mean. I will check if it is nil.
    – skilled-solutions
    Nov 23 '18 at 12:49










  • @WarrenBurton It is not nil, i added a check and start is executed.
    – skilled-solutions
    Nov 23 '18 at 12:56
















0














Im totally helpless right now, i'm trying to send an eMail for data upload in an iOS Swift 4 App. I found the Obj-C Mailcore library which works in normal code, for example in a button press callback. But if i'm trying to use the same code in my AppDelegate fetch func it doesn't return from the completionHandler.



The Mailcore send operation is async so i used a semaphore wrapper around it, but the completion handler is never called.



Edit:



Apparently the code does not work in the button with the Semaphore. Only if i remove the



let _ = semaphore.wait(timeout: DispatchTime.distantFuture)


part.



So is there another way to wait for the completion of the async completionBlock?




Yes, look at my answer :-)



My code:



let smtpSession = MCOSMTPSession()
[...]
let sendOperation = smtpSession.sendOperation(with: rfc822Data!)
[...]
let semaphore = DispatchSemaphore(value: 0)
if (sendOperation != nil) {
print("Starting sendOperation...")
sendOperation?.start { (error) -> Void in
if (error != nil) {
sendingError = true
print("Error sending email: (error)")
} else {
print("Successfully sent email!")
}
sendingDone = true
semaphore.signal()
}
let _ = semaphore.wait(timeout: DispatchTime.distantFuture)
} else {
print("Cant init sendOperation")
sendingError = true
}









share|improve this question
























  • Are you sure sendOperation is not-nil when you call start ? Theres nothing special about an object that adopts UIApplicationDelegate
    – Warren Burton
    Nov 23 '18 at 12:23










  • @Warren Burton Im not sure, but i just copy and pasted it from the button code where it worked so i doesnt bothered. I will check this but shouldnt it crash if i call start() on a nil object?
    – skilled-solutions
    Nov 23 '18 at 12:25










  • sendOperation appears to be Optional from your code. You can see that from sendOperation? using optional chaining.
    – Warren Burton
    Nov 23 '18 at 12:41












  • @Warren Burton Now i see what you mean. I will check if it is nil.
    – skilled-solutions
    Nov 23 '18 at 12:49










  • @WarrenBurton It is not nil, i added a check and start is executed.
    – skilled-solutions
    Nov 23 '18 at 12:56














0












0








0







Im totally helpless right now, i'm trying to send an eMail for data upload in an iOS Swift 4 App. I found the Obj-C Mailcore library which works in normal code, for example in a button press callback. But if i'm trying to use the same code in my AppDelegate fetch func it doesn't return from the completionHandler.



The Mailcore send operation is async so i used a semaphore wrapper around it, but the completion handler is never called.



Edit:



Apparently the code does not work in the button with the Semaphore. Only if i remove the



let _ = semaphore.wait(timeout: DispatchTime.distantFuture)


part.



So is there another way to wait for the completion of the async completionBlock?




Yes, look at my answer :-)



My code:



let smtpSession = MCOSMTPSession()
[...]
let sendOperation = smtpSession.sendOperation(with: rfc822Data!)
[...]
let semaphore = DispatchSemaphore(value: 0)
if (sendOperation != nil) {
print("Starting sendOperation...")
sendOperation?.start { (error) -> Void in
if (error != nil) {
sendingError = true
print("Error sending email: (error)")
} else {
print("Successfully sent email!")
}
sendingDone = true
semaphore.signal()
}
let _ = semaphore.wait(timeout: DispatchTime.distantFuture)
} else {
print("Cant init sendOperation")
sendingError = true
}









share|improve this question















Im totally helpless right now, i'm trying to send an eMail for data upload in an iOS Swift 4 App. I found the Obj-C Mailcore library which works in normal code, for example in a button press callback. But if i'm trying to use the same code in my AppDelegate fetch func it doesn't return from the completionHandler.



The Mailcore send operation is async so i used a semaphore wrapper around it, but the completion handler is never called.



Edit:



Apparently the code does not work in the button with the Semaphore. Only if i remove the



let _ = semaphore.wait(timeout: DispatchTime.distantFuture)


part.



So is there another way to wait for the completion of the async completionBlock?




Yes, look at my answer :-)



My code:



let smtpSession = MCOSMTPSession()
[...]
let sendOperation = smtpSession.sendOperation(with: rfc822Data!)
[...]
let semaphore = DispatchSemaphore(value: 0)
if (sendOperation != nil) {
print("Starting sendOperation...")
sendOperation?.start { (error) -> Void in
if (error != nil) {
sendingError = true
print("Error sending email: (error)")
} else {
print("Successfully sent email!")
}
sendingDone = true
semaphore.signal()
}
let _ = semaphore.wait(timeout: DispatchTime.distantFuture)
} else {
print("Cant init sendOperation")
sendingError = true
}






ios swift swift4 appdelegate mailcore2






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 26 '18 at 7:25







skilled-solutions

















asked Nov 23 '18 at 12:13









skilled-solutionsskilled-solutions

216




216












  • Are you sure sendOperation is not-nil when you call start ? Theres nothing special about an object that adopts UIApplicationDelegate
    – Warren Burton
    Nov 23 '18 at 12:23










  • @Warren Burton Im not sure, but i just copy and pasted it from the button code where it worked so i doesnt bothered. I will check this but shouldnt it crash if i call start() on a nil object?
    – skilled-solutions
    Nov 23 '18 at 12:25










  • sendOperation appears to be Optional from your code. You can see that from sendOperation? using optional chaining.
    – Warren Burton
    Nov 23 '18 at 12:41












  • @Warren Burton Now i see what you mean. I will check if it is nil.
    – skilled-solutions
    Nov 23 '18 at 12:49










  • @WarrenBurton It is not nil, i added a check and start is executed.
    – skilled-solutions
    Nov 23 '18 at 12:56


















  • Are you sure sendOperation is not-nil when you call start ? Theres nothing special about an object that adopts UIApplicationDelegate
    – Warren Burton
    Nov 23 '18 at 12:23










  • @Warren Burton Im not sure, but i just copy and pasted it from the button code where it worked so i doesnt bothered. I will check this but shouldnt it crash if i call start() on a nil object?
    – skilled-solutions
    Nov 23 '18 at 12:25










  • sendOperation appears to be Optional from your code. You can see that from sendOperation? using optional chaining.
    – Warren Burton
    Nov 23 '18 at 12:41












  • @Warren Burton Now i see what you mean. I will check if it is nil.
    – skilled-solutions
    Nov 23 '18 at 12:49










  • @WarrenBurton It is not nil, i added a check and start is executed.
    – skilled-solutions
    Nov 23 '18 at 12:56
















Are you sure sendOperation is not-nil when you call start ? Theres nothing special about an object that adopts UIApplicationDelegate
– Warren Burton
Nov 23 '18 at 12:23




Are you sure sendOperation is not-nil when you call start ? Theres nothing special about an object that adopts UIApplicationDelegate
– Warren Burton
Nov 23 '18 at 12:23












@Warren Burton Im not sure, but i just copy and pasted it from the button code where it worked so i doesnt bothered. I will check this but shouldnt it crash if i call start() on a nil object?
– skilled-solutions
Nov 23 '18 at 12:25




@Warren Burton Im not sure, but i just copy and pasted it from the button code where it worked so i doesnt bothered. I will check this but shouldnt it crash if i call start() on a nil object?
– skilled-solutions
Nov 23 '18 at 12:25












sendOperation appears to be Optional from your code. You can see that from sendOperation? using optional chaining.
– Warren Burton
Nov 23 '18 at 12:41






sendOperation appears to be Optional from your code. You can see that from sendOperation? using optional chaining.
– Warren Burton
Nov 23 '18 at 12:41














@Warren Burton Now i see what you mean. I will check if it is nil.
– skilled-solutions
Nov 23 '18 at 12:49




@Warren Burton Now i see what you mean. I will check if it is nil.
– skilled-solutions
Nov 23 '18 at 12:49












@WarrenBurton It is not nil, i added a check and start is executed.
– skilled-solutions
Nov 23 '18 at 12:56




@WarrenBurton It is not nil, i added a check and start is executed.
– skilled-solutions
Nov 23 '18 at 12:56












2 Answers
2






active

oldest

votes


















0














The completion is either coming on the same thread or runs something in that thread.



The normal thing to do is to not wait, but instead do whatever you need to do after it completes in the completion itself.



If you must do it with a semaphore, move the start call to another thread.






share|improve this answer





























    0














    So i found a solution:



    SyncManager.swift



    import Foundation

    /// A generic Cocoa-Style completion handler
    typealias CompletionHandler = (Error?) -> Void

    /// Provides syncronous access to results returned by
    /// asynchronous processes with completion handlers
    class SyncMaker {
    var result: Error? = nil

    /// Generates a synchronous-compliant completion handler
    func completion() -> CompletionHandler{
    return {
    (error: Error?) in

    // Store result, return control
    self.result = error
    CFRunLoopStop(CFRunLoopGetCurrent())
    }
    }

    // Perform task (that must use custom completion handler) and wait
    func run(_ task: @escaping () -> Void) -> Error? {
    task()
    CFRunLoopRun()
    return result
    }
    }


    AppDelegate.swift (partly)



    [...]
    let syncMaker = SyncMaker()
    let result = syncMaker.run {
    sendOperation?.start(
    syncMaker.completion())
    }
    if (result != nil) {
    print("Error sending email: (result)")
    } else {
    sendingError = false
    print("Successfully sent email!")
    }
    [...]





    share|improve this answer





















      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53446533%2fswift-how-to-send-email-mail-in-appdelegate-fetch%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      0














      The completion is either coming on the same thread or runs something in that thread.



      The normal thing to do is to not wait, but instead do whatever you need to do after it completes in the completion itself.



      If you must do it with a semaphore, move the start call to another thread.






      share|improve this answer


























        0














        The completion is either coming on the same thread or runs something in that thread.



        The normal thing to do is to not wait, but instead do whatever you need to do after it completes in the completion itself.



        If you must do it with a semaphore, move the start call to another thread.






        share|improve this answer
























          0












          0








          0






          The completion is either coming on the same thread or runs something in that thread.



          The normal thing to do is to not wait, but instead do whatever you need to do after it completes in the completion itself.



          If you must do it with a semaphore, move the start call to another thread.






          share|improve this answer












          The completion is either coming on the same thread or runs something in that thread.



          The normal thing to do is to not wait, but instead do whatever you need to do after it completes in the completion itself.



          If you must do it with a semaphore, move the start call to another thread.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 23 '18 at 14:37









          Lou FrancoLou Franco

          74.3k14115173




          74.3k14115173

























              0














              So i found a solution:



              SyncManager.swift



              import Foundation

              /// A generic Cocoa-Style completion handler
              typealias CompletionHandler = (Error?) -> Void

              /// Provides syncronous access to results returned by
              /// asynchronous processes with completion handlers
              class SyncMaker {
              var result: Error? = nil

              /// Generates a synchronous-compliant completion handler
              func completion() -> CompletionHandler{
              return {
              (error: Error?) in

              // Store result, return control
              self.result = error
              CFRunLoopStop(CFRunLoopGetCurrent())
              }
              }

              // Perform task (that must use custom completion handler) and wait
              func run(_ task: @escaping () -> Void) -> Error? {
              task()
              CFRunLoopRun()
              return result
              }
              }


              AppDelegate.swift (partly)



              [...]
              let syncMaker = SyncMaker()
              let result = syncMaker.run {
              sendOperation?.start(
              syncMaker.completion())
              }
              if (result != nil) {
              print("Error sending email: (result)")
              } else {
              sendingError = false
              print("Successfully sent email!")
              }
              [...]





              share|improve this answer


























                0














                So i found a solution:



                SyncManager.swift



                import Foundation

                /// A generic Cocoa-Style completion handler
                typealias CompletionHandler = (Error?) -> Void

                /// Provides syncronous access to results returned by
                /// asynchronous processes with completion handlers
                class SyncMaker {
                var result: Error? = nil

                /// Generates a synchronous-compliant completion handler
                func completion() -> CompletionHandler{
                return {
                (error: Error?) in

                // Store result, return control
                self.result = error
                CFRunLoopStop(CFRunLoopGetCurrent())
                }
                }

                // Perform task (that must use custom completion handler) and wait
                func run(_ task: @escaping () -> Void) -> Error? {
                task()
                CFRunLoopRun()
                return result
                }
                }


                AppDelegate.swift (partly)



                [...]
                let syncMaker = SyncMaker()
                let result = syncMaker.run {
                sendOperation?.start(
                syncMaker.completion())
                }
                if (result != nil) {
                print("Error sending email: (result)")
                } else {
                sendingError = false
                print("Successfully sent email!")
                }
                [...]





                share|improve this answer
























                  0












                  0








                  0






                  So i found a solution:



                  SyncManager.swift



                  import Foundation

                  /// A generic Cocoa-Style completion handler
                  typealias CompletionHandler = (Error?) -> Void

                  /// Provides syncronous access to results returned by
                  /// asynchronous processes with completion handlers
                  class SyncMaker {
                  var result: Error? = nil

                  /// Generates a synchronous-compliant completion handler
                  func completion() -> CompletionHandler{
                  return {
                  (error: Error?) in

                  // Store result, return control
                  self.result = error
                  CFRunLoopStop(CFRunLoopGetCurrent())
                  }
                  }

                  // Perform task (that must use custom completion handler) and wait
                  func run(_ task: @escaping () -> Void) -> Error? {
                  task()
                  CFRunLoopRun()
                  return result
                  }
                  }


                  AppDelegate.swift (partly)



                  [...]
                  let syncMaker = SyncMaker()
                  let result = syncMaker.run {
                  sendOperation?.start(
                  syncMaker.completion())
                  }
                  if (result != nil) {
                  print("Error sending email: (result)")
                  } else {
                  sendingError = false
                  print("Successfully sent email!")
                  }
                  [...]





                  share|improve this answer












                  So i found a solution:



                  SyncManager.swift



                  import Foundation

                  /// A generic Cocoa-Style completion handler
                  typealias CompletionHandler = (Error?) -> Void

                  /// Provides syncronous access to results returned by
                  /// asynchronous processes with completion handlers
                  class SyncMaker {
                  var result: Error? = nil

                  /// Generates a synchronous-compliant completion handler
                  func completion() -> CompletionHandler{
                  return {
                  (error: Error?) in

                  // Store result, return control
                  self.result = error
                  CFRunLoopStop(CFRunLoopGetCurrent())
                  }
                  }

                  // Perform task (that must use custom completion handler) and wait
                  func run(_ task: @escaping () -> Void) -> Error? {
                  task()
                  CFRunLoopRun()
                  return result
                  }
                  }


                  AppDelegate.swift (partly)



                  [...]
                  let syncMaker = SyncMaker()
                  let result = syncMaker.run {
                  sendOperation?.start(
                  syncMaker.completion())
                  }
                  if (result != nil) {
                  print("Error sending email: (result)")
                  } else {
                  sendingError = false
                  print("Successfully sent email!")
                  }
                  [...]






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 25 '18 at 13:48









                  skilled-solutionsskilled-solutions

                  216




                  216






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53446533%2fswift-how-to-send-email-mail-in-appdelegate-fetch%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      What visual should I use to simply compare current year value vs last year in Power BI desktop

                      Alexandru Averescu

                      Trompette piccolo