iOS Swift 2.1 - Error Handling using Try Catch - ios

I am trying to do Error handling using swift 2.1,
The following scenario,
var test: NSArray! = ["Test1", "Test2"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
do{
try testing()
} catch {
print("error")
}
}
func testing() throws {
print(test.objectAtIndex(7))
}
At the above case, My application crashes & saying terminating with uncaught exception of type NSException but I am expecting the control is supposed to be inside the Catch block instead of crash.
May I know the solution for this. Can anybody please do the needful on this

The only way you can make that work is to throw an error (as Eric D. pointed out in the comments):
Playground:
enum ArrayError : ErrorType{
case OutOfBounds
}
class SomeClass {
var test: NSArray! = ["Test1", "Test2"]
func testCode() {
do{
try testing(3)
} catch let error{
print("error = \(error)") // for index 3 this would print "error = OutOfBounds\n"
}
}
func testing(index: Int) throws -> String {
guard index < test.count else{
throw ArrayError.OutOfBounds
}
return test[index] as! String
}
}
let sC = SomeClass()
sC.testCode()

Related

Realm crashing app on delete or write, libc++abi.dylib: terminating with uncaught exception of type NSException

I have added realm integration in my app. Process is that,
1] if list is not empty then reload the tableview , and at the same time call an api, receive its response..
2] check value present against Id or not, if present delete that value from realm, again add value to realm and reload the tableview.. Code is working fine, if i wait for the 2nd step completion. But 2nd step is totally asynchronous..Here is what I have tried
And crash is happening when i change viewcontroller before the completion 2nd step.
public class Features : Object , Codable{
#objc dynamic var intellinectsId : String?
#objc dynamic var serviceName : String?
#objc dynamic var android_icon : String?
#objc dynamic var parentUrl : String?
#objc dynamic var url : String?
#objc dynamic var mobileOrder : String?
enum CodingKeys: String, CodingKey {
case serviceName = "serviceName"
case android_icon = "android_icon"
case parentUrl = "parentUrl"
case url = "url"
case mobileOrder = "mobileOrder"
case intellinectsId = "intellinectsId"
}
required convenience public init(from decoder: Decoder) throws {
self.init()
let values = try decoder.container(keyedBy: CodingKeys.self)
serviceName = try values.decodeIfPresent(String.self, forKey: .serviceName)
android_icon = try values.decodeIfPresent(String.self, forKey: .android_icon)
parentUrl = try values.decodeIfPresent(String.self, forKey: .parentUrl)
url = try values.decodeIfPresent(String.self, forKey: .url)
mobileOrder = try values.decodeIfPresent(String.self, forKey: .mobileOrder)
intellinectsId = try values.decodeIfPresent(String.self, forKey: .intellinectsId)
}
required init() {
}
}
I have created single class for RealmService
class RealmService {
private init() {}
/// To get singleton class
static let shared = RealmService()
/// To get realm object instance
var realm = try! Realm()
/// To create a record or adding new object to database
func create<T: Object>(_ object: T) {
do {
try realm.safeWrite {
//realm.add(object)
realm.create(T.self,value: object)
//realm.create(T.self, value: object, update: .modified)
}
} catch {
post(error)
}
}
/// To update/modify particular record/object in the database
func update<T: Object>(_ object: T, with dictionary: [String: Any?]) {
do {
try realm.write {
for (key, value) in dictionary {
object.setValue(value, forKey: key)
}
realm.add(object, update: .all) //add(object, update: true)
}
} catch {
post(error)
}
}
/// To delete/remove record or object database
func delete<T: Object>(_ object: T) {
do {
try realm.write {
realm.delete(object)
}
} catch {
post(error)
}
}
/// To handle the errors while performing realmDB opration
func post(_ error: Error) {
NotificationCenter.default.post(name: NSNotification.Name("RealmError"), object: error)
}
/// To observe realm error in the particular View controller
func observeErrors(in vc: UIViewController, completionHandler: #escaping(Error?) -> Void) {
NotificationCenter.default.addObserver(forName: NSNotification.Name("RealmError"), object: nil, queue: nil) { (notification) in
completionHandler(notification.object as? Error)
}
}
/// To stop observing errors in particular View Controller
func stopObservingErrors(in vc: UIViewController) {
NotificationCenter.default.removeObserver(vc, name: NSNotification.Name("RealmError"), object: nil)
}
/// To delete complete realm form the app
func completeDeleteRealm() {
let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
let realmURLs = [
realmURL,
realmURL.appendingPathExtension("lock"),
realmURL.appendingPathExtension("note"),
realmURL.appendingPathExtension("management")
]
for URL in realmURLs {
do {
try FileManager.default.removeItem(at: URL)
} catch {
post(error)
}
}
}
}
Now in View controller , I am taking a value from realm, against id, like this
var dashboardList : Results<Features>{
get{
return RealmService.shared.realm.objects(Features.self).filter(NSPredicate(format: "intellinectsId == %#", HelperFunctions().getUserInfoFromDefaults()?.intellinectsId ?? ""))
}
}
.. as given in step 1st, if dashboardList count is > 0 then reload the tableview , simultaneously , call and api to fetch the details and again I have performed 2nd step like below
if let responseList = response.array, responseList.count > 0{
//remove existing data from realm
let removeHMC = RealmService.shared.realm.objects(Features.self).filter(NSPredicate(format: "intellinectsId == %#",intellinectsId))
if let realm = try? Realm(){
try? realm.write {
realm.delete(removeHMC)
}
}
if let featuresList = responseList[0]["features"].array, featuresList.count > 0{
for val in featuresList{
let feature = Features()
feature.intellinectsId = intellinectsId
feature.serviceName = val["serviceName"].string
feature.android_icon = val["android_icon"].string
feature.parentUrl = val["parentUrl"].string
feature.url = val["url"].string
feature.mobileOrder = val["mobileOrder"].string
RealmService.shared.create(feature)
}
}
}
And if i wait for this completion then it works fine. but if i go on next vc. I am getting an error like
libc++abi.dylib: terminating with uncaught exception of type NSException
after looking at the specific issue, I received an error
Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'
I applied this trick also.. But after deleting value from realm , showing again to the tableview causes this issue. I am unable to figure out. Kindly help
In your response when you are deleting the previous features list you are creating a new instance of Realm() which will cause inconsistencies between those two.
Try removing that and using the same RealmService.shared like this
//remove existing data from realm
let removeHMC = RealmService.shared.realm.objects(Features.self).filter(NSPredicate(format: "intellinectsId == %#",intellinectsId))
RealmService.shared.delete(removeHMC)

What is the "uncaught exception"? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 5 years ago.
Improve this question
I'm trying to build a simple iPhone app that saves user entered text to iCloud, using a UITextView and a UIButton. I've never done something like this, so I'm following this tutorial. So far their tutorials have worked flawlessly for me, until this one. The app builds fine, and runs on my iPhone, displaying a place to enter text, and a button to save the text to iCloud. But when I tap the screen to enter text, the app crashes with this message:
2017-03-24 08:45:56.093572 Gaethr2[6342:1419021] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSMetadataQuery valueOfAttribute:forResultAtIndex:]: index (0) out of bounds (0)'
*** First throw call stack:
(0x184b611b8 0x18359855c 0x184b61100 0x1855f1460 0x100056ffc 0x10005857c 0x184afab10 0x184afa214 0x184af9f90 0x184b69b8c 0x184a3be64 0x185570e0c 0x1855ef268 0x184afab10 0x184afa214 0x184af9f90 0x184b69b8c 0x184a3be64 0x185570e0c 0x1968d93e4 0x1968db29c 0x184b0ea44 0x184b0e240 0x184b0c094 0x184a3a2b8 0x1864ee198 0x18aa817fc 0x18aa7c534 0x10005b720 0x183a1d5b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
Message from debugger: failed to send the k packet
Here's the ViewController code:
import UIKit
class ViewController: UIViewController
{
#IBOutlet weak var textView: UITextView!
var document: MyDocument?
var documentURL: URL?
var ubiquityURL: URL?
var metaDataQuery: NSMetadataQuery?
func metadataQueryDidFinishGathering(notification: NSNotification) -> Void
{
let query: NSMetadataQuery = notification.object as! NSMetadataQuery
query.disableUpdates()
NotificationCenter.default.removeObserver(self,
name: NSNotification.Name.NSMetadataQueryDidFinishGathering,
object: query)
query.stop()
let resultURL = query.value(ofAttribute: NSMetadataItemURLKey,
forResultAt: 0) as! URL
if query.resultCount == 1 {
let resultURL = query.value(ofAttribute: NSMetadataItemURLKey,
forResultAt: 0) as! URL
document = MyDocument(fileURL: resultURL as URL)
document?.open(completionHandler: {(success: Bool) -> Void in
if success {
print("iCloud file open OK")
self.textView.text = self.document?.userText
self.ubiquityURL = resultURL as URL
} else {
print("iCloud file open failed")
}
})
} else {
document = MyDocument(fileURL: ubiquityURL!)
document?.save(to: ubiquityURL!,
for: .forCreating,
completionHandler: {(success: Bool) -> Void in
if success {
print("iCloud create OK")
} else {
print("iCloud create failed")
}
})
}
}
override func viewDidLoad()
{
super.viewDidLoad()
let filemgr = FileManager.default
ubiquityURL = filemgr.url(forUbiquityContainerIdentifier: nil)
guard ubiquityURL != nil else {
print("Unable to access iCloud Account")
print("Open the Settings app and enter your Apple ID into iCloud settings")
return
}
ubiquityURL = ubiquityURL?.appendingPathComponent(
"Documents/savefile.txt")
metaDataQuery = NSMetadataQuery()
metaDataQuery?.predicate =
NSPredicate(format: "%K like 'savefile.txt'",
NSMetadataItemFSNameKey)
metaDataQuery?.searchScopes =
[NSMetadataQueryUbiquitousDocumentsScope]
NotificationCenter.default.addObserver(self,
selector: #selector(
ViewController.metadataQueryDidFinishGathering),
name: NSNotification.Name.NSMetadataQueryDidFinishGathering,
object: metaDataQuery!)
metaDataQuery!.start()
}
#IBAction func saveDocument(_ sender: AnyObject)
{
document!.userText = textView.text
document?.save(to: ubiquityURL!,
for: .forOverwriting,
completionHandler: {(success: Bool) -> Void in
if success {
print("Save overwrite OK")
} else {
print("Save overwrite failed")
}
})
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here's the code for MyDocument.Swift
import UIKit
class MyDocument: UIDocument
{
var userText: String? = "Some Sample Text"
override func contents(forType typeName: String) throws -> Any
{
if let content = userText
{
let length =
content.lengthOfBytes(using: String.Encoding.utf8)
return NSData(bytes:content, length: length)
}
else
{
return Data()
}
}
override func load(fromContents contents: Any, ofType typeName: String?) throws
{
if let userContent = contents as? Data
{
userText = NSString(bytes: (contents as AnyObject).bytes,
length: userContent.count,
encoding: String.Encoding.utf8.rawValue) as? String
}
}
}
Here's a screenshot of the crash:
Thank you for your help!
The uncaught exception is
-[NSMetadataQuery valueOfAttribute:forResultAtIndex:]: index (0) out of bounds (0)'
Delete the first occurrence of
let resultURL = query.value(ofAttribute: NSMetadataItemURLKey,
forResultAt: 0) as! URL
It's redundant and causes the error if query.results is empty

App Crashes SIGABRT when trying to use Realm

I am trying to save a simple object with Realm but the app keeps crashing when trying to make a write transaction even when it's wrapped in a Do Catch block.
let theme = Theme()
theme.name = "Custom Theme"
theme.backgroundColor = backgroundColor
theme.accentColor = accentColor
theme.numberColor = numColor
theme.functionColor = funcColor
// Add to the Realm inside a transaction
do {
try Realm().write {
do {
try Realm().add(theme, update: true)
} catch {
print("Error saving data")
}
}
} catch {
print("Realm.write error")
}
Here is the object 'Theme'
class Theme : Object {
dynamic var name = ""
dynamic var backgroundColor = ""
dynamic var accentColor = ""
dynamic var numberColor = ""
dynamic var functionColor = ""
override static func primaryKey() -> String? {
return "name"
}
}
Here is a screenshot of the crash
SIGABRT Crash
EDIT: The code above that causes the crash is only executed when a button is clicked. There is no console output either. I am bringing realm in via CocoaPods.
Ah, it might have something to do with the way you're creating the realm instances, try this:
let realm = try! Realm()
do {
try realm.write {
do {
try realm.add(theme, update: true)
} catch {
print("Error saving data")
}
}
} catch {
print("Realm.write error")
}
Though, usually you won't need to wrap your transactions into a do-catch block:
let realm = try! Realm()
try! realm.write {
realm.add(theme, update: true)
}

CoreData fetch does not always return value

What I want to do is store data using core data.
I've got code like below with fetching, my problem is that sometimes when I run application wpis2.count gives 0 no idea why (i've got information: "data not loaded" without any error). Is there any way that I should prepare core data before use?
Ustawienia are:
extension Ustawienia {
#NSManaged var ust: String?
#NSManaged var wym: String?
}
PS. Data exists for sure, because when I run application again it works OK. Any idea how solve it?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let entity2 = NSFetchRequest(entityName: "Ustawienia")
entity2.fetchLimit = 1
do{
let wpis2 = try moc3.executeFetchRequest(entity2) as! [NSManagedObject]
let ust = wpis2 as [NSManagedObject]
if (wpis2.count==1){
let ustawienia = wpis2[0] as! Ustawienia
if (ustawienia.ust=="n"){
tabela="n"
}
else
{
tabela="p"
}
if (ustawienia.wym=="w"){
wymienniki="w"
}
else
{
wymienniki="p"
}
}
else
{
NSLog("data not loaded")
}
}
catch
{
fatalError("error \(error)")
}
}

RealmSwift in iOS issue with 'write' block

I am getting one more issue regarding write block - 'SharedRealm.realm.write()' - Error - "Call can throw, but it is not marked with 'try' and the error is not handled", how it can be handled.
This is the code:
func addItems(items:[Item]) {
do {
let rlm = try Realm()
rlm.write { () -> Void in
for item in items {
rlm.add(item, update: true)
}
}
}
catch let rlmError {
print("Realm() generated error: \(rlmError)")
}
}
Still I am getting the same error - ":13: Call can throw but is not marked with 'try'"
rlm.write { ... } might throw an error as well as the initializer so you will need to add the try operator in front of this invocation, too.
Since Realm() might throw an error you'll need to wrap it in a do { try } catch block
extension Realm {
public class func saveClosure(dbClosure: (Realm)->()) {
do {
let rlm = try Realm()
rlm.write { () -> Void in
dbClosure(rlm)
}
}
catch let rlmError{
print("Realm() generated error: \(rlmError)")
}
}
}
Checkout https://gist.github.com/edwardIshaq/b5810ab35c30df10af24

Resources