FBSDKLoginKit is crashing for unknown reason on iOS11.3 version - fbsdk

#IBAction func didTapLogainAction(_ sender: Any) {
let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
fbLoginManager.logIn(withReadPermissions: ["email"], from: self) { (result, error) in
if (error == nil){
let fbloginresult : FBSDKLoginManagerLoginResult = result!
if fbloginresult.grantedPermissions != nil {
if(fbloginresult.grantedPermissions.contains("email")) {
if((FBSDKAccessToken.current()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil){
let dict = result as! [String : AnyObject]
FBSDKLoginManager().logOut()
}
})
}
}
}
}
}
}
Facebook login, when i'm press continue from facebook interface, it crashing on my iOS11.3 version. it quitely working good in ios11.4 and iOS11.03 lowers versions.

It got resolved by the Facebook developer team. Meanwhile, we have to use the following snippet for iOS11.3. If older Methods also will work i think.
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(app, open: url, options: options)
}

Related

Nesting URLSession.shared.dataTask in Swift 4

I am trying to fetch data from an api where the JSON returned has URLs to other pieces of information that I need, such as
"value1" : "data",
"value2": {
"url": "https://example.com/stuff",
}
My logic is as follows:
func(completion: #escaping ([Data]) -> ()) {
var classArray = [myClass]()
URLSession.shared.dataTask(with: url) { (data, _, _) in
guard let data = data else { return }
do {
guard let resultArray = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { return }
let myObject = myClass(value1: resultArray["value1"]! as! String)
guard let valueUrl = URL(string: resultArray["value2"]! as! String) else { return }
URLSession.shared.dataTask(with: valueUrl) { (data, _, _) in
myObject.value2 = data
classArray.append(myObject)
}.resume()
} catch let error {
print("Failed to create json with error: ", error.localizedDescription)
}
completion(classArray)
}.resume()
}
}
Is this a valid approach or are there better implementations? Trying to avoid a future Pyramid of Doom situation. I have tried putting the inner URLSession call in a separate private function but still receive an empty classArray in the end.

Core data context crash

I am working on save image to core data. I used image pick to select image,
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let currentDateTime = Date()
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
self.imagePickedBlock?(image,currentDateTime)
} else {
print("Something went wrong")
}
viewController?.dismiss(animated: true, completion:{
if let addPhotoViewController = self.completionViewController as? AddPhotoViewController {
guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {return }
addPhotoViewController.photoViewModel.image = image
self.viewController?.present(addPhotoViewController, animated: true, completion: nil)
}
})
}
and in addPhotoViewController, I have an confirme button to call the following update database method.
The Photo is an NSManagedObject.
private func updateDatabase(with photoViewModels: [PhotoViewModel]) {
container?.performBackgroundTask { [weak self] context in
for photoViewModel in (self?.photoViewModels)! {
_ = try? Photo.findOrCreatePhoto(matching: photoViewModel, in: context)
}
try? context.save()
self?.printDatabaseStatistics()
}
}
And this is the create NSManagedObject method.
static func findOrCreatePhoto(matching photoViewModel: PhotoViewModel, in context: NSManagedObjectContext) throws -> Photo {
let request : NSFetchRequest<Photo> = Photo.fetchRequest()
// request.predicate if Needed
do {
let matches = try context.fetch(request)
if matches.count > 0 {
return matches[0]
}
} catch {
throw error
}
let photo = Photo(context:context) // the crash line
photo.image = UIImageJPEGRepresentation(photoViewModel.image!, 1)
photo.uploadDate = photoViewModel.createDate
photo.text = photoViewModel.description
// photo.group = try? Group.findOrCreateGroup(matching: photoViewModel, in: context)
return photo
}.
It marks "Enqueued from com.apple.main-thread", I don't really understand where is the problem exactly about the thread, anyone has idea? Don't hesitate if I didn't explain clear enough :)
Thank you for your time.

How do I save data using NSKeyedArchiver?

I am very close to finishing my first iOS App using Swift 4 and iOS 11.
The app has a list displayed in a table view controller and a detail view with a UITextView object that is editable. My goal is for the user to be able to make edits to the content in the UITextView and save those changes using NSKeyedArchiver.
I have the list view complete and the detail view connected. You can make edits but they do not save.
I have confirmed that the entry does save to memory that persists beyond the session, but the edits do not save.
Reviews of documentation and working through multiple tutorials have not provided the insights needed. I have attached a screen shot to show the interface of the detail view and here is the code from the detail view controller where the save button triggers the Save action:
import UIKit
import os.log
class ViewController: UIViewController, UINavigationControllerDelegate, UITextViewDelegate {
var season: Season?
//MARK: Properties
#IBOutlet weak var seasonDetail: UITextView!
#IBAction func saveButton(_ sender: UIBarButtonItem) {
if let selectedDetail = seasonDetail.text {
seasonDetail.text = selectedDetail
} else {
print("failed to save changes.")
}
saveChanges()
print("Save button clicked")
}
override func viewDidLoad() {
super.viewDidLoad()
title = season?.name
seasonDetail.text = season?.detail
seasonDetail.delegate=self
}
override func viewWillDisappear(_ animated: Bool) {
season?.detail = (seasonDetail?.text)!
}
func textViewDidEndEditing(_ textView: UITextView) {
seasonDetail.text = season?.detail
}
//MARK: UITextViewdDelegate
func textViewShouldReturn(_ textView: UITextView) -> Bool {
textView.resignFirstResponder()
return true
}
func saveChanges() {
print("Saving items to: \(Season.ArchiveURL)")
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(season as Any, toFile: Season.ArchiveURL.path)
if isSuccessfulSave {
os_log("Season sucessfully saved.", log: OSLog.default, type: .debug)
} else {
os_log("Failed to save season.", log: OSLog.default, type: .debug)
}
}
}
Here is the code from the data model class:
import UIKit
import os.log
class Season: NSObject, NSCoding {
//MARK: Properties
var name: String
var detail: String
//MARK: Archiving Paths
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("season")
//MARK: Types
struct PropertyKey {
static let name = "name"
static let detail = "detail"
}
//MARK: Initialization
init?(name: String, detail: String) {
guard !name.isEmpty else {
return nil
}
guard !detail.isEmpty else {
return nil
}
// Initialize stored properties
self.name = name
self.detail = detail
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: PropertyKey.name)
aCoder.encode(detail, forKey: PropertyKey.detail)
}
required convenience init?(coder aDecoder: NSCoder) {
// the name is required. If we cannnot get a name string, the initializer should fail.
guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String
else {
os_log("Unable to decode the name for a Season object.", log: OSLog.default, type: .debug)
return nil
}
let detail = aDecoder.decodeObject(forKey: PropertyKey.detail)
self.init(name: name, detail: detail as! String)
}
}
My goal is to understand what is missing with my code and know how to persist all the data, including the edits. I would appreciate any direction that would help.
Please check :
class ViewController: UIViewController, UINavigationControllerDelegate, UITextViewDelegate {
var season: Season?
#IBOutlet weak var seasonDetail: UITextView!
#IBAction func saveButton(_ sender: UIBarButtonItem) {
if let selectedDetail = seasonDetail.text {
season?.detail = selectedDetail // this is the line
} else {
print("failed to save changes.")
}
saveChanges()
print("Save button clicked")
}
override func viewDidLoad() {
super.viewDidLoad()
if season == nil {
season = Season(name: "Season Name", detail: "Season Details")
}
title = season?.name
seasonDetail.text = season?.detail
seasonDetail.delegate=self
}
override func viewWillDisappear(_ animated: Bool) {
season?.detail = (seasonDetail?.text)!
}
func textViewDidEndEditing(_ textView: UITextView) {
season?.detail = seasonDetail.text
}
//MARK: UITextViewdDelegate
func textViewShouldReturn(_ textView: UITextView) -> Bool {
textView.resignFirstResponder()
return true
}
func saveChanges() {
print("Saving items to: \(Season.ArchiveURL)")
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(season as Any, toFile: Season.ArchiveURL.path)
if isSuccessfulSave {
os_log("Season sucessfully saved.", log: OSLog.default, type: .debug)
} else {
os_log("Failed to save season.", log: OSLog.default, type: .debug)
}
}
}

App Crashed due to Invalid signature for pointer dequeued from free list in UIImagePickerController

I am facing problem in UIImagePickerController selection. When I choose source from Photo Library App crashes due to Invalid signature for pointer dequeued from free list. then If I run again it works fine with the same code. I searched on google and found one question related to my query Xcode - My app crash and the error is "Invalid pointer dequeued from free list *** set a breakpoint in malloc_error_break to debug" .
but solution isn't working in my case.
I am using Xcode 8.1 and my deployment Target is 8.0.
As #luke requested for the code for UIImagePickerViewController:
let pickerView = UIImagePickerController()
pickerView.delegate = self
pickerView.allowsEditing = true
pickerView.sourceType = .photoLibrary
let authStatus = PHPhotoLibrary.authorizationStatus() // Get the current authorization state.
// print(authStatus)
if (authStatus == PHAuthorizationStatus.notDetermined) {
// Access has not been determined.
PHPhotoLibrary.requestAuthorization({ (newStatus) in
if (newStatus == PHAuthorizationStatus.authorized) {
self.present(pickerView, animated: true, completion: { _ in })
}
else {
}
})
} else if authStatus == PHAuthorizationStatus.authorized {
print("Access has been granted.")
self.present(pickerView, animated: true, completion: { _ in })
} else if (authStatus == PHAuthorizationStatus.denied) {
print("Access has been denied.")
}
else if (authStatus == PHAuthorizationStatus.restricted) {
print("Restricted access - normally won't happen.")
}
Now when the user picks a particular image:
This method will be called:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
//print(info)
if let pickedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
YOUR_GLOBAL_IMAGE_VIEW?.contentMode = .scaleAspectFit
YOUR_GLOBAL_IMAGE_VIEW?.image = pickedImage
}
}
dismiss(animated: true, completion: nil)
}
Don't forget to import PhotosUI and UIImagePickerControllerDelegate.

Convert Data to String in Swift 3

I am very new to Swift.
I want to create something like API on Swift for my educational app.
I have this code:
static func getFilm(filmID: Int) -> String {
print("getFilm")
let url = URL(string: "https://api.kinopoisk.cf/getFilm?filmID=\(filmID)")!
var request = URLRequest(url: url)
var returnData: String = ""
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if var responseVar = response, var dataVar = data {
print(responseVar)
returnData = String(data: dataVar, encoding: .utf8)
} else {
print(error)
}
}
task.resume()
return returnData
}
And I try to convert Data to String in this line: returnData = String(data: dataVar, encoding: .utf8)
Swift compiler gives me an error, and change this line to
returnData = String(data: dataVar, encoding: .utf8)!
, when I execute this line I get empty returnData variable.
If I use basic example line
print(String(data: data, encoding: .utf8))
everything will be OK and I can see data in XCode console.
So, how I can convert Data to String?
This is an example using a completion handler:
class func getFilm(filmID: Int, completion: #escaping (String) -> ()) {
let url = URL(string: "https://api.kinopoisk.cf/getFilm?filmID=\(filmID)")!
URLSession.shared.dataTask(with:url) { (data, response, error) in
if error != nil {
print(error!)
completion("")
} else {
if let returnData = String(data: data!, encoding: .utf8) {
completion(returnData)
} else {
completion("")
}
}
}.resume()
}
And you call it
MyClass.getFilm(filmID:12345) { result in
print(result)
}
In case of an error the completion handler returns an empty string.
MyClass is the enclosing class of getFilm method. Most likely the web service will return JSON, so you might need to deserialize the JSON to an array or dictionary.
In a more sophisticated version create an enum with two cases and associated values
enum ConnectionResult {
case success(String), failure(Error)
}
With a little more effort demonstrating the subtle power of Swift you can return either the converted string on success of the error on failure in a single object.
class func getFilm(filmID: Int, completion: #escaping (ConnectionResult) -> ()) {
let url = URL(string: "https://api.kinopoisk.cf/getFilm?filmID=\(filmID)")!
URLSession.shared.dataTask(with:url) { (data, response, error) in
if error != nil {
completion(.failure(error!))
} else {
if let returnData = String(data: data!, encoding: .utf8) {
completion(.success(returnData))
} else {
completion(.failure(NSError(domain: "myDomain", code: 9999, userInfo: [NSLocalizedDescriptionKey : "The data is not converible to 'String'"])))
}
}
}.resume()
}
On the caller side a switch statement separates the cases.
MyClass.getFilm(filmID:12345) { result in
switch result {
case .success(let string) : print(string)
case .failure(let error) : print(error)
}
}
I had this problem, you can't use encoding: .utf8 for unpredictable data. It will return nil every time.
Use this instead:
String(decoding: data, as: UTF8.self)
For anyone coming in future (which are probably not interested in OP's film code?!);
Simply, try something like:
extension Data {
public func toString() -> String {
return String(data: self, encoding: .utf8) ?? "";
}
}
See also my toHex related answer

Resources