Unable to load Today Extension with table view - ios8-today-widget

I really could need some help...
I try to use a today extension to get some stuff and refresh a cell with data from a SOAP request. It works like a charm in simulator but on a actual device (iPhone 6 Plus) widget updates the cell and shortly afterwards switches to "Unable to Load".
The app shows > 20 MB in the profiler and I read the max size is only about 10 MB. But how can this be when I'm only showing - mostely - one single table view cell? The whole SOAP Framework has 2.6 MB... This is driving me crazy...
And... wouldn't there be some memory error in the log instead of "Feature not available in extensions of type com.apple.widget-extension"? I don't think my crash is related to the size, the screenshot below shows the crash with a widget size of 4 MB.
Does anyone have some experience with this kind of struggle?
What I can provide:
My TodayViewController:
import CoreData
import NotificationCenter
class TodayViewController: UITableViewController, NCWidgetProviding {
struct CellConstants {
static let parkingProcess = "ParkingProcessCell"
static let login = "LoginCell"
static let noTransactions = "NoTransactionsCell"
}
var loadedParkingProcesses: [MCParkingProcess] = []
var loggedInInternal = false
var noTransactions = false
var reload = true
var fetchingData = false
var loggedIn: Bool {
get {
let defaults = NSUserDefaults(suiteName: "group.not.relevant.here")
loggedInInternal = defaults?.stringForKey("username") != nil &&
defaults?.stringForKey("password") != nil
? true : false
return loggedInInternal
}
}
func resetTimer() {
print("timer reset")
reload = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
print("memory warning!")
}
func loadData(username: String, password: String) {
if fetchingData {
return
}
fetchingData = true
guard reload == true else {
let _ = NSTimer(timeInterval: 10, target: self, selector: #selector(TodayViewController.resetTimer), userInfo: nil, repeats: false)
return
}
reload = false
let locale = NSLocale.preferredLanguages()[ 0].componentsSeparatedByString("-")[0]
MCSoapClient.sharedInstance().loadRunningParkingProcessesForUsername (username, password: password, language: locale, completion: { statusCode, result in
guard let dict = result as? [String: AnyObject] else {
// no dict. something's wrong.
return
}
if Int(dict["statuscode"] as! String)! % 100 != 0 {
// some error from our backend
return
}
if let parkingProcess = dict["parkvorgang"] {
self.noTransactions = false
if let pp = parkingProcess as? [AnyObject] {
// more than one
self.loadedParkingProcesses = MCParkingProcess.parkingProcessesFromJSON(pp) as! [ MCParkingProcess]
} else {
// only one process
self.loadedParkingProcesses = [MCParkingProcess( fromJSON: parkingProcess as! [String: AnyObject])]
}
} else {
// no transactions
self.noTransactions = true
}
self.fetchingData = false
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
self.resetContentSize()
})
}, failed: { result, error in
print("failed with error: \(error)")
print("result: \(result)")
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
self.resetContentSize()
})
self.fetchingData = false
})
self.resetContentSize()
}
override func viewDidLoad() {
tableView.backgroundColor = UIColor.clearColor()
}
override func viewWillAppear(animated: Bool) {
performFetch()
}
override func tableView(tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return !loggedIn || noTransactions
? 1
: loadedParkingProcesses.count
}
func RGBColor(r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) -> UIColor {
return UIColor(red: (r / 255), green: (g / 255), blue: (b / 255), alpha: (a))
}
func loadDetailsForCell(cell: MCParkingProcessCell, withParkingProcess parkingProcess: MCParkingProcess) {
let locale = NSLocale.preferredLanguages()[ 0].componentsSeparatedByString("-")[0]
let defaults = NSUserDefaults(suiteName: "group.not.relevant.here")
if let username = defaults?.stringForKey("username")
, password = defaults?.stringForKey("password") {
// Load current parkingProcess costs
MCSoapClient.sharedInstance().loadCurrentCostsforParkingProc essesID(parkingProcess.ID, username: username, password: password, parkingProcessStartTimeStamp: "", language: locale, completion: { statusCode, result in
guard let dict = result as? [String: AnyObject] else {
// no dict. something's wrong.
return
}
if Int(dict["statuscode"] as! String)! % 100 != 0 {
// some error from our backend
return
}
var elapsedMinutes = Int(dict["dauer"] as! String)!
if parkingProcess.parkingZone.isAboZone {
let serverTime = Int(dict["serverzeit"] as! String)
let usedParkingTimeInSeconds = Double(serverTime!) - parkingProcess.startedAt.timeIntervalSince1970
elapsedMinutes = Int(usedParkingTimeInSeconds) / 60
}
// update currentCosts
parkingProcess.updateCurrentCostsFromJSON( dict["parkvorgang"] as? [String: AnyObject])
parkingProcess.updateCurrentParkingTime(elapsedMinutes)
// set label text
let someNumber = parkingProcess.currentCosts
let numberFormatter: NSNumberFormatter = NSNumberFormatter()
numberFormatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
numberFormatter.minimumFractionDigits = 2
numberFormatter.maximumFractionDigits = 2
numberFormatter.decimalSeparator = ","
cell.costsLabel.text = "\( numberFormatter.stringFromNumber(someNumber)!) €"
cell.timeLabel.text = String.formatMinutesToCorrectTime( parkingProcess.currentParkingTime.intValue)
}, failed: { result, error in
print("failed with error: \(error)")
print("result: \(result)")
})
}
}
func configureRunningParkingProcessCell(cell: MCParkingProcessCell, withParkingProcess parkingProcess: MCParkingProcess) {
cell.backgroundView?.backgroundColor = UIColor.clearColor()
cell.addressLabel.textColor = UIColor.whiteColor()
cell.parkingZoneIDLabel.text = parkingProcess.parkingZone.number
cell.addressLabel.text = parkingProcess.parkingZone.parkingZoneID
cell.costsLabel.text = parkingProcess.parkingZone.costs
cell.carPlateLabel.text = parkingProcess.usedCarPlate
cell.maxDurationLabel.text = NSDateFormatter.localizedStringFromDate (parkingProcess.endedAt, dateStyle: NSDateFormatterStyle.MediumStyle, timeStyle: NSDateFormatterStyle.ShortStyle)
cell.dateLabel.text = NSDateFormatter.localizedStringFromDate( parkingProcess.startedAt, dateStyle: NSDateFormatterStyle.MediumStyle, timeStyle: NSDateFormatterStyle.ShortStyle)
// starts an async request to get current costs and time
self.loadDetailsForCell(cell, withParkingProcess: parkingProcess)
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if !loggedInInternal {
let cell = tableView.dequeueReusableCellWithIdentifier( CellConstants.login) as! LoginCell
cell.extensionContext = extensionContext
return cell
}
if noTransactions {
return tableView.dequeueReusableCellWithIdentifier( CellConstants.noTransactions)!
}
let cell = tableView.dequeueReusableCellWithIdentifier( CellConstants.parkingProcess, forIndexPath: indexPath) as! MCParkingProcessCell
// empty here. will be filled with second request
cell.timeLabel.text = ""
cell.costsLabel.text = ""
cell.accessoryView = MSCellAccessory(type: MSCellAccessoryType.DISCLOSURE_INDICATOR, color: RGBColor(91, g: 181, b: 148, a: 1))
configureRunningParkingProcessCell(cell, withParkingProcess: self.loadedParkingProcesses[indexPath.row])
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return !loggedInInternal || noTransactions
? 50
: 120
}
func resetContentSize() {
dispatch_async(dispatch_get_main_queue(), {
self.preferredContentSize = self.tableView.contentSize
})
}
override func awakeFromNib() {
super.awakeFromNib()
resetContentSize()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
resetContentSize()
}
func performFetch() {
let defaults = NSUserDefaults(suiteName: "group.not.relevant.here")
if let username = defaults?.stringForKey("username")
, password = defaults?.stringForKey("password") {
loadData(username, password: password)
} else {
// not updated in loaddata(), so it is here
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
self.resetContentSize()
})
}
}
func widgetMarginInsetsForProposedMarginInsets
(defaultMarginInsets: UIEdgeInsets) -> (UIEdgeInsets) {
return UIEdgeInsetsZero
}
func widgetPerformUpdateWithCompletionHandler(
completionHandler: ((NCUpdateResult) -> Void)) {
performFetch()
completionHandler(NCUpdateResult.NoData)
}
override func tableView(tableView: UITableView,
didSelectRowAtIndexPath indexPath: NSIndexPath) {
if !loggedInInternal || noTransactions {
return
}
let urlAsString = "mcsmartparking://parkingProcess=\( loadedParkingProcesses[indexPath.row].ID)"
let url = NSURL(string: urlAsString)
self.extensionContext!.openURL(url!, completionHandler: nil)
tableView.deselectRowAtIndexPath(indexPath, animated: false)
}
}
And my error:
2016-04-14 12:56:08.322 TodayExtension_Dev[11656:320804] *** Assertion failure in void _UIApplicationAssertForExtensionType(NSArray *__strong)(), /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.10/UIApplication.m:2521
* thread #1: tid = 0x4e524, 0x00000001801d7f48 libobjc.A.dylib`objc_exception_throw, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001801d7f48 libobjc.A.dylib`objc_exception_throw
frame #1: 0x0000000180b72d20 CoreFoundation`+[NSException raise:format:arguments:] + 108
frame #2: 0x00000001814f81c0 Foundation`-[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 88
frame #3: 0x0000000185f76ff0 UIKit`_UIApplicationAssertForExtensionType + 484
frame #4: 0x0000000186143818 UIKit`_UIAlertControllerCommonInit + 112
frame #5: 0x0000000186143aa8 UIKit`-[UIAlertController initWithNibName:bundle:] + 104
frame #6: 0x0000000186143b24 UIKit`+[UIAlertController alertControllerWithTitle:message:preferredStyle:] + 100
frame #7: 0x0000000100133518 TodayExtension_Dev`__20+[a5987398 a2489290]_block_invoke + 64
frame #8: 0x00000001805bd4bc libdispatch.dylib`_dispatch_call_block_and_release + 24
frame #9: 0x00000001805bd47c libdispatch.dylib`_dispatch_client_callout + 16
frame #10: 0x00000001805c2b84 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 1844
frame #11: 0x0000000180b28df0 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
frame #12: 0x0000000180b26c58 CoreFoundation`__CFRunLoopRun + 1628
frame #13: 0x0000000180a50e80 CoreFoundation`CFRunLoopRunSpecific + 384
frame #14: 0x0000000182338088 GraphicsServices`GSEventRunModal + 180
frame #15: 0x0000000185d3a0c8 UIKit`UIApplicationMain + 204
frame #16: 0x0000000180814ce0 libxpc.dylib`_xpc_objc_main + 784
frame #17: 0x00000001808169dc libxpc.dylib`xpc_main + 200
frame #18: 0x0000000181633d60 Foundation`-[NSXPCListener resume] + 172
frame #19: 0x0000000187e72c48 PlugInKit`-[PKService run] + 544
frame #20: 0x0000000187e728dc PlugInKit`+[PKService main] + 56
frame #21: 0x0000000187e72c6c PlugInKit`+[PKService _defaultRun:arguments :] + 20
frame #22: 0x0000000181446058 libextension.dylib`NSExtensionMain + 64
frame #23: 0x00000001805ee8b8 libdyld.dylib`start + 4
* thread #1: tid = 0x4e524, 0x00000001801ca7d4 libc++abi.dylib`__cxa_throw, queue = 'com.apple.main-thread', stop reason = breakpoint 1.2
* frame #0: 0x00000001801ca7d4 libc++abi.dylib`__cxa_throw
frame #1: 0x00000001801d8094 libobjc.A.dylib`objc_exception_throw + 332
frame #2: 0x0000000180b72d20 CoreFoundation`+[NSException raise:format: arguments:] + 108
frame #3: 0x00000001814f81c0 Foundation`-[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 88
frame #4: 0x0000000185f76ff0 UIKit`_UIApplicationAssertForExtensionType + 484
frame #5: 0x0000000186143818 UIKit`_UIAlertControllerCommonInit + 112
frame #6: 0x0000000186143aa8 UIKit`-[UIAlertController initWithNibName: bundle:] + 104
frame #7: 0x0000000186143b24 UIKit`+[UIAlertController alertControllerWithTitle:message:preferredStyle:] + 100
frame #8: 0x0000000100133518 TodayExtension_Dev`__20+[a5987398 a2489290]_block_invoke + 64
frame #9: 0x00000001805bd4bc libdispatch. dylib`_dispatch_call_block_and_release + 24
frame #10: 0x00000001805bd47c libdispatch.dylib`_dispatch_client_callout + 16
frame #11: 0x00000001805c2b84 libdispatch. dylib`_dispatch_main_queue_callback_4CF + 1844
frame #12: 0x0000000180b28df0 CoreFoundation `__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
frame #13: 0x0000000180b26c58 CoreFoundation`__CFRunLoopRun + 1628
frame #14: 0x0000000180a50e80 CoreFoundation`CFRunLoopRunSpecific + 384
frame #15: 0x0000000182338088 GraphicsServices`GSEventRunModal + 180
frame #16: 0x0000000185d3a0c8 UIKit`UIApplicationMain + 204
frame #17: 0x0000000180814ce0 libxpc.dylib`_xpc_objc_main + 784
frame #18: 0x00000001808169dc libxpc.dylib`xpc_main + 200
frame #19: 0x0000000181633d60 Foundation`-[NSXPCListener resume] + 172
frame #20: 0x0000000187e72c48 PlugInKit`-[PKService run] + 544
frame #21: 0x0000000187e728dc PlugInKit`+[PKService main] + 56
frame #22: 0x0000000187e72c6c PlugInKit`+[PKService _defaultRun:arguments :] + 20
frame #23: 0x0000000181446058 libextension.dylib`NSExtensionMain + 64
frame #24: 0x00000001805ee8b8 libdyld.dylib`start + 4
2016-04-14 12:56:08.401 TodayExtension_Dev[11656:320804] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Feature not available in extensions of type com.apple.widget-extension'
*** First throw call stack:
(0x180b72e50 0x1801d7f80 0x180b72d20 0x1814f81c0 0x185f76ff0 0x186143818 0x186143aa8 0x186143b24 0x100133518 0x1805bd4bc 0x1805bd47c 0x1805c2b84 0x180b28df0 0x180b26c58 0x180a50e80 0x182338088 0x185d3a0c8 0x180814ce0 0x1808169dc 0x181633d60 0x187e72c48 0x187e728dc 0x187e72c6c 0x181446058 0x1805ee8b8)
libc++abi.dylib: terminating with uncaught exception of type NSException
And a screenshot of the crash:
And more:
dlopen(/System/Library/Frameworks/CoreText.framework/CoreText, 0x00000002)
dlopen(/System/Library/Frameworks/CoreText.framework/CoreText) ==> 0xffeeddcc00007000
dlsym(0xffeeddcc00007000, CTFontCreateWithGraphicsFont)
dlsym(0xffeeddcc00007000, CTFontCreateWithGraphicsFont) ==> 0x183a68cf4
dlsym(0xffeeddcc00007000, CTFontGetGlyphsAndAdvancesForCharacterRange)
dlsym(0xffeeddcc00007000, CTFontGetGlyphsAndAdvancesForCharacterRange) ==> 0x183a79754
dlsym(0xffeeddcc00007000, CTFontCopyAvailableTables)
dlsym(0xffeeddcc00007000, CTFontCopyAvailableTables) ==> 0x183abe2b8
dlsym(0xffeeddcc00007000, CTFontCopyCharacterSet)
dlsym(0xffeeddcc00007000, CTFontCopyCharacterSet) ==> 0x183a6c2dc
dlsym(0xffeeddcc00007000, CTFontCopyGraphicsFont)
dlsym(0xffeeddcc00007000, CTFontCopyGraphicsFont) ==> 0x183a67acc
dlsym(0xffeeddcc00007000, CTFontGetUnitsPerEm)
dlsym(0xffeeddcc00007000, CTFontGetUnitsPerEm) ==> 0x183a8fe20
dlsym(0xffeeddcc00007000, CTFontGetAscent)
dlsym(0xffeeddcc00007000, CTFontGetAscent) ==> 0x183a6a380
dlsym(0xffeeddcc00007000, CTFontGetDescent)
dlsym(0xffeeddcc00007000, CTFontGetDescent) ==> 0x183a6c020
dlsym(0xffeeddcc00007000, CTFontGetLeading)
dlsym(0xffeeddcc00007000, CTFontGetLeading) ==> 0x183a6c0bc
dlsym(0xffeeddcc00007000, CTFontIsLastResort)
dlsym(0xffeeddcc00007000, CTFontIsLastResort) ==> 0x183a6c274
dlsym(0xffeeddcc00007000, CTFontGetSymbolicTraits)
dlsym(0xffeeddcc00007000, CTFontGetSymbolicTraits) ==> 0x183a84a30
dlsym(0xffeeddcc00007000, CTFontGetSize)
dlsym(0xffeeddcc00007000, CTFontGetSize) ==> 0x183a65118
dlsym(0xffeeddcc00007000, CTFontCopyFamilyName)
dlsym(0xffeeddcc00007000, CTFontCopyFamilyName) ==> 0x183a6a088
dlsym(0xffeeddcc00007000, CTFontCopyFullName)
dlsym(0xffeeddcc00007000, CTFontCopyFullName) ==> 0x183a8febc
dlsym(0xffeeddcc00007000, CTFontSwapDefaultSize)
dlsym(0xffeeddcc00007000, CTFontSwapDefaultSize) ==> 0x183a65114
dlsym(0xffeeddcc00007000, CTFontGetClientObject)
dlsym(0xffeeddcc00007000, CTFontGetClientObject) ==> 0x183a651a0
dlsym(0xffeeddcc00007000, CTFontSetClientObject)
dlsym(0xffeeddcc00007000, CTFontSetClientObject) ==> 0x183a698a4
dlsym(0xffeeddcc00007000, CTFontDescriptorCreateForUIType)
dlsym(0xffeeddcc00007000, CTFontDescriptorCreateForUIType) ==> 0x183a77ac0
dlsym(0xffeeddcc00007000, CTFontDescriptorCreateCopyWithSymbolicTraits)
dlsym(0xffeeddcc00007000, CTFontDescriptorCreateCopyWithSymbolicTraits) ==> 0x183a828d0
dlsym(0xffeeddcc00007000, CTFontCreateWithFontDescriptorAndOptions)
dlsym(0xffeeddcc00007000, CTFontCreateWithFontDescriptorAndOptions) ==> 0x183abc2c8
dlsym(0xffeeddcc00007000, CTFontCopyFontDescriptor)
dlsym(0xffeeddcc00007000, CTFontCopyFontDescriptor) ==> 0x183a616f0
dlsym(0xffeeddcc00007000, CTFontDescriptorIsSystemUIFont)
dlsym(0xffeeddcc00007000, CTFontDescriptorIsSystemUIFont) ==> 0x183a6a06c
dlsym(0xffeeddcc00007000, CTFontManagerInstalledFontsChanged)
dlsym(0xffeeddcc00007000, CTFontManagerInstalledFontsChanged) ==> 0x183b35e04
dlsym(0xffeeddcc00007000, CTFontRemoveFromCaches)
dlsym(0xffeeddcc00007000, CTFontRemoveFromCaches) ==> 0x183abf878
dlopen(/System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation, 0x00000002)
dlopen(/System/Library/PrivateFrameworks/UIFoundation.framework/UIFoundation) ==> 0xffeeddcc00009000
dlsym(0xffeeddcc00009000, UINewFont)
dlsym(0xffeeddcc00009000, UINewFont) ==> 0x186506a24
dlopen(/System/Library/PrivateFrameworks/FontServices.framework/libGSFontCache.dylib, 0x00000002)
dyld: loaded: /System/Library/PrivateFrameworks/FontServices.framework/libGSFontCache.dylib
dyld_image_path_containing_address(0x1958cc000)
dlopen(/System/Library/PrivateFrameworks/FontServices.framework/libGSFontCache.dylib, 0x00000010)
dlopen(/System/Library/PrivateFrameworks/FontServices.framework/libGSFontCache.dylib) ==> 0xffeeddcc0002d400
dlopen(/System/Library/PrivateFrameworks/FontServices.framework/libGSFontCache.dylib) ==> 0xffeeddcc0002d400
dlsym(0xffeeddcc0002d400, GSFontCacheGetDictionary)
dlsym(0xffeeddcc0002d400, GSFontCacheGetDictionary) ==> 0x1958cd1f0
dlopen(/System/Library/Frameworks/UIKit.framework/UIKit, 0x00000002)
dlopen(/System/Library/Frameworks/UIKit.framework/UIKit) ==> 0xffeeddcc00009100
dlsym(0xffeeddcc00009100, _UIApplicationUsesAlternateUI)
dlsym(0xffeeddcc00009100, _UIApplicationUsesAlternateUI) ==> 0x186810224
dlsym(0xffeeddcc00009100, _UIApplicationLinkedOnOrAfter)
dlsym(0xffeeddcc00009100, _UIApplicationLinkedOnOrAfter) ==> 0x186563cc0
dlopen(/usr/lib/libAccessibility.dylib, 0x00000005)
dlopen(/usr/lib/libAccessibility.dylib) ==> 0xffeeddcc00008500
dlsym(0xffeeddcc00008500, _AXSEnhanceTextLegibilityEnabled)
dlsym(0xffeeddcc00008500, _AXSEnhanceTextLegibilityEnabled) ==> 0x184a709d8
dlopen(/System/Library/Frameworks/UIKit.framework/UIKit, 0x00000002)
dlopen(/System/Library/Frameworks/UIKit.framework/UIKit) ==> 0xffeeddcc00009100
dlopen(/System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib, 0x00000005)
dlopen(/System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib) ==> 0xffeeddcc00006d00
dlsym(0xffeeddcc00006d00, FPFontCreateFontsWithPath)
dlsym(0xffeeddcc00006d00, FPFontCreateFontsWithPath) ==> 0x1838f4b68
dlsym(0xffeeddcc00006d00, FPFontRetain)
dlsym(0xffeeddcc00006d00, FPFontRetain) ==> 0x1838f7f30
dlsym(0xffeeddcc00006d00, FPFontCopyTable)
dlsym(0xffeeddcc00006d00, FPFontCopyTable) ==> 0x1838f81e0
dlsym(0xffeeddcc00006d00, FPFontCopyTable)
dlsym(0xffeeddcc00006d00, FPFontCopyTable) ==> 0x1838f81e0
dlsym(0xffeeddcc00006d00, FPFontCopyNames)
dlsym(0xffeeddcc00006d00, FPFontCopyNames) ==> 0x1838f88ec
dlsym(0xffeeddcc00006d00, FPFontGetPostScriptName)
dlsym(0xffeeddcc00006d00, FPFontGetPostScriptName) ==> 0x1838f8bd4
dlsym(0xffeeddcc00006d00, FPFontGetNumberOfGlyphs)...
dlsym(0xffeeddcc00006d00, FPFontIsBitmapOnly)
dlsym(0xffeeddcc00006d00, FPFontIsBitmapOnly) ==> 0x1838fd100
dlsym(0xffeeddcc00006d00, FPFontGetGlyphIdealAdvanceWidth)
dlsym(0xffeeddcc00006d00, FPFontGetGlyphIdealAdvanceWidth) ==> 0x1838fd28c
dlsym(0xffeeddcc00006d00, FPFontGetUnitsPerEm)
dlsym(0xffeeddcc00006d00, FPFontGetUnitsPerEm) ==> 0x1838fa254
dlopen(/System/Library/Frameworks/UIKit.framework/UIKit, 0x00000002)
dlopen(/System/Library/Frameworks/UIKit.framework/UIKit) ==> 0xffeeddcc00009100
dlsym(0xffeeddcc00009100, UIGraphicsGetCurrentContext)
dlsym(0xffeeddcc00009100, UIGraphicsGetCurrentContext) ==> 0x1865718e8
dlsym(0xffeeddcc00006d00, FPFontIsBitmapOnly)
dlsym(0xffeeddcc00006d00, FPFontIsBitmapOnly) ==> 0x1838fd100
dlsym(0xffeeddcc00006d00, FPFontCopyGlyphPath)
dlsym(0xffeeddcc00006d00, FPFontCopyGlyphPath) ==> 0x1838fdbb0
dlopen(/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics, 0x00000009)
dlopen(/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics) ==> 0xffeeddcc00004000
dlsym(0xffeeddcc00004000, CGPathCreateMutable)
dlsym(0xffeeddcc00004000, CGPathCreateMutable) ==> 0x1829117fc
dlsym(0xffeeddcc00004000, CGPathRelease)
dlsym(0xffeeddcc00004000, CGPathRelease) ==> 0x182912294
dlsym(0xffeeddcc00004000, CGPathMoveToPoint)
dlsym(0xffeeddcc00004000, CGPathMoveToPoint) ==> 0x182912380
dlsym(0xffeeddcc00004000, CGPathAddLineToPoint)
dlsym(0xffeeddcc00004000, CGPathAddLineToPoint) ==> 0x182912440
dlsym(0xffeeddcc00004000, CGPathAddCurveToPoint)
dlsym(0xffeeddcc00004000, CGPathAddCurveToPoint) ==> 0x182912630
dlsym(0xffeeddcc00004000, CGPathAddQuadCurveToPoint)
dlsym(0xffeeddcc00004000, CGPathAddQuadCurveToPoint) ==> 0x18291252c
dlsym(0xffeeddcc00004000, CGPathCloseSubpath)
dlsym(0xffeeddcc00004000, CGPathCloseSubpath) ==> 0x18291274c
dlsym(0xffeeddcc00004000, CGFontIndexMapAddRange)
dlsym(0xffeeddcc00004000, CGFontIndexMapAddRange) ==> 0x1829c53a4
dlsym(0xffeeddcc00004000, CGPathCreateByNormalizingGlyphPath)
dlsym(0xffeeddcc00004000, CGPathCreateByNormalizingGlyphPath) ==> 0x182913c64
dlsym(0xffeeddcc00004000, CGPathCreateCopyByTransformingPath)
dlsym(0xffeeddcc00004000, CGPathCreateCopyByTransformingPath) ==> 0x182911cc4
dlsym(0xffeeddcc00004000, CGPathRetain)
dlsym(0xffeeddcc00004000, CGPathRetain) ==> 0x182912268
dlsym(0xffeeddcc00004000, CGPathIsEmpty)
dlsym(0xffeeddcc00004000, CGPathIsEmpty) ==> 0x18291353c
dlsym(0xffeeddcc00004000, CGPathGetBoundingBox)
dlsym(0xffeeddcc00004000, CGPathGetBoundingBox) ==> 0x1829139dc
dyld_image_header_containing_address(0x181f15cf4)
_dyld_get_image_slide(0x181ce8000)
_dyld_get_image_slide(0x181ce8000)
2016-06-13 15:22:33.862 TodayExtension_Dev[5335:67225] *** Assertion failure in void _UIApplicationAssertForExtensionType( NSArray *__strong)(), /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.12/UIApplication.m:2521
dyld_image_header_containing_address(0x181614e32)
_dyld_get_image_slide(0x1812dc000)
_dyld_get_image_slide(0x1812dc000)
2016-06-13 15:22:33.863 TodayExtension_Dev[5335:67225] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Feature not available in extensions of type com.apple.widget-extension'
*** First throw call stack:
(0x181406db0 0x180a6bf80 0x181406c80 0x181d8c1c0 0x18680afb0 0x1869d77d8 0x1869d7a68 0x1869d7ae4 0x1000b2f68 0x180e514bc 0x180e5147c 0x180e56b84 0x1813bcd50 0x1813babb8 0x1812e4c50 0x182bcc088 0x1865ce088 0x1810a8ce0 0x1810aa9dc 0x181ec7d60 0x188706c48 0x1887068dc 0x188706c6c 0x181cda058 0x180e828b8)
libc++abi.dylib: terminating with uncaught exception of type NSException

From your stack trace, it looks like you're trying to display a UIAlertController:
frame #6: 0x0000000186143b24 UIKit`+[UIAlertController alertControllerWithTitle:message:preferredStyle:] + 100
frame #7: 0x0000000100133518 TodayExtension_Dev`__20+[a5987398 a2489290]_block_invoke + 64
UIAlertController is presented modally over the entire screen, and your widget does not have access to the entire screen, so they are not allowed in Today Widgets.
I think you need to get to the bottom of why an alert is showing. Perhaps a side effect of your SOAP client?

Related

[PFUserAuthenticationController registerAuthenticationProvider:]: unrecognized selector sent to instance 0x7f96c1fa6090

Getting this error in the logs:
2016-03-18 18:53:54.915 Tinder[715:229250] -[PFUserAuthenticationController registerAuthenticationProvider:]: unrecognized selector sent to instance 0x7f96c1fa6090
2016-03-18 18:53:54.919 Tinder[715:229250] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PFUserAuthenticationController registerAuthenticationProvider:]: unrecognized selector sent to instance 0x7f96c1fa6090'
*** First throw call stack:
(
0 CoreFoundation 0x0000000102e2ae65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000104f0fdeb objc_exception_throw + 48
2 CoreFoundation 0x0000000102e3348d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000102d8090a ___forwarding___ + 970
4 CoreFoundation 0x0000000102d804b8 _CF_forwarding_prep_0 + 120
5 Tinder 0x000000010249506a +[PFFacebookUtils initializeFacebookWithApplicationLaunchOptions:] + 225
6 Tinder 0x00000001023b3ccd _TFC6Tinder11AppDelegate11applicationfS0_FTCSo13UIApplication29didFinishLaunchingWithOptionsGSqGVSs10DictionaryCSo8NSObjectPSs9AnyObject____Sb + 541
7 Tinder 0x00000001023b4a53 _TToFC6Tinder11AppDelegate11applicationfS0_FTCSo13UIApplication29didFinishLaunchingWithOptionsGSqGVSs10DictionaryCSo8NSObjectPSs9AnyObject____Sb + 179
8 UIKit 0x00000001039e31f1 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 272
9 UIKit 0x00000001039e4397 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3415
10 UIKit 0x00000001039eacc6 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1760
11 UIKit 0x00000001039e7e7b -[UIApplication workspaceDidEndTransaction:] + 188
12 FrontBoardServices 0x000000010657e754 -[FBSSerialQueue _performNext] + 192
13 FrontBoardServices 0x000000010657eac2 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
14 CoreFoundation 0x0000000102d56a31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
15 CoreFoundation 0x0000000102d4c95c __CFRunLoopDoSources0 + 556
16 CoreFoundation 0x0000000102d4be13 __CFRunLoopRun + 867
17 CoreFoundation 0x0000000102d4b828 CFRunLoopRunSpecific + 488
18 UIKit 0x00000001039e77cd -[UIApplication _run] + 402
19 UIKit 0x00000001039ec610 UIApplicationMain + 171
20 Tinder 0x00000001023b57ad main + 109
21 libdyld.dylib 0x0000000105a5a92d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Also getting an error in my code:
Thread 1: signal SIGABRT
but I don't yet have any outlets in my code.
My code in AppDelegate.swift (personal info replaced by "xxx"):
import UIKit
import Parse
import Bolts
// If you want to use any of the UI components, uncomment this line
// import ParseUI
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
//--------------------------------------
// MARK: - UIApplicationDelegate
//--------------------------------------
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Enable storing and querying data from Local Datastore.
// Remove this line if you don't want to use Local Datastore features or want to use cachePolicy.
Parse.enableLocalDatastore()
let parseConfiguration = ParseClientConfiguration(block: { (ParseMutableClientConfiguration) -> Void in
ParseMutableClientConfiguration.applicationId = "xxx"
ParseMutableClientConfiguration.clientKey = "xxx"
ParseMutableClientConfiguration.server = "https://yourapp.herokuapp.com/parse"
})
Parse.initializeWithConfiguration(parseConfiguration)
PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)
PFUser.enableAutomaticUser()
let defaultACL = PFACL();
// If you would like all objects to be private by default, remove this line.
defaultACL.publicReadAccess = true
PFACL.setDefaultACL(defaultACL, withAccessForCurrentUser:true)
if application.applicationState != UIApplicationState.Background {
// Track an app open here if we launch with a push, unless
// "content_available" was used to trigger a background push (introduced in iOS 7).
// In that case, we skip tracking here to avoid double counting the app-open.
let preBackgroundPush = !application.respondsToSelector("backgroundRefreshStatus")
let oldPushHandlerOnly = !self.respondsToSelector("application:didReceiveRemoteNotification:fetchCompletionHandler:")
var noPushPayload = false;
if let options = launchOptions {
noPushPayload = options[UIApplicationLaunchOptionsRemoteNotificationKey] != nil;
}
if (preBackgroundPush || oldPushHandlerOnly || noPushPayload) {
PFAnalytics.trackAppOpenedWithLaunchOptions(launchOptions)
}
}
if application.respondsToSelector("registerUserNotificationSettings:") {
let userNotificationTypes: UIUserNotificationType = [UIUserNotificationType.Alert, UIUserNotificationType.Badge, UIUserNotificationType.Sound]
let settings = UIUserNotificationSettings(forTypes: userNotificationTypes, categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
} else {
let types: UIRemoteNotificationType = [UIRemoteNotificationType.Badge, UIRemoteNotificationType.Alert, UIRemoteNotificationType.Sound]
application.registerForRemoteNotificationTypes(types)
}
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
//--------------------------------------
// MARK: Push Notifications
//--------------------------------------
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
let installation = PFInstallation.currentInstallation()
installation.setDeviceTokenFromData(deviceToken)
installation.saveInBackground()
// PFPush.subscribeToChannelInBackground("") { (succeeded: Bool, error: NSError?) in
// if succeeded {
// print("ParseStarterProject successfully subscribed to push notifications on the broadcast channel.");
// } else {
// print("ParseStarterProject failed to subscribe to push notifications on the broadcast channel with error = %#.", error)
// }
// }
}
func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
if error.code == 3010 {
print("Push notifications are not supported in the iOS Simulator.")
} else {
print("application:didFailToRegisterForRemoteNotificationsWithError: %#", error)
}
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
PFPush.handlePush(userInfo)
if application.applicationState == UIApplicationState.Inactive {
PFAnalytics.trackAppOpenedWithRemoteNotificationPayload(userInfo)
}
}
func application(application: UIApplication,
openURL url: NSURL,
sourceApplication: String?,
annotation: AnyObject) -> Bool {
return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}
func applicationDidBecomeActive(application: UIApplication) {
FBSDKAppEvents.activateApp()
}
}
I managed to fix this error doing the following:
First I deployed the official version of Parse Server (instead of Rob's version). Open this link and click 'Deploy to Heroku', follow the steps.
https://github.com/ParsePlatform/parse-server-example
After that I downloaded the Parse Frameworks (including Facebook framework) from the link below and replaced all current frameworks in my project with these frameworks downloaded.
https://parse.com/downloads/ios/parse-library/latest
Other than that just follow the class steps (adding code to AppDelegate, Info.pslist e etc.
Any problems, let me know.
Check this link : Parse - Facebook SDK Exception
I think the problem is in this line of code:
PFFacebookUtils.initializeFacebookWithApplicationLaunchOptions(launchOptions)
I see that you are using latest Facebook and Parse version. But are you sure the latest versions are referenced? (maybe in podspecs, or podfile). Try the old good command to delete Derived Data (cmd + shift + k and cmd + shift + alt + k)
This kind of error are due to a nil object referencing a method class. Check if this is happening also.

querying an object with a pointer - parse, swift2

I have 2 classes, I have an Activity Class and JobPost class, in my Activity class there is an object called "postedJob" which is a pointer(JobPost), it stores the objectID of every job posted.
What I am trying to achieve is to query the postedJob from activity, but my code below form parse is throwing an error.
let jobPostObject = PFObject(className: "JobPost")
let query = PFQuery(className: "Activity")
query.whereKey("postedJob", equalTo: jobPostObject)
let objects = query.findObjects()
print(objects)
I dont understand why it's returning this error below
'Tried to save an object with a new, unsaved child.'
*** First throw call stack:
(
0 CoreFoundation 0x0000000108213f45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000107c8bdeb objc_exception_throw + 48
2 CoreFoundation 0x0000000108213e7d +[NSException raise:format:] + 205
3 post 0x00000001063c5e92 -[PFPointerObjectEncoder encodeParseObject:] + 108
4 post 0x00000001063c5324 -[PFEncoder encodeObject:] + 113
5 post 0x00000001063948ef __129+[PFRESTQueryCommand findCommandParametersWithOrder:conditions:selectedKeys:includedKeys:limit:skip:extraOptions:tracingEnabled:]_block_invoke97 + 1808
6 CoreFoundation 0x0000000108180cb5 __65-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 85
7 CoreFoundation 0x0000000108180bbd -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] + 237
8 post 0x00000001063940fd +[PFRESTQueryCommand findCommandParametersWithOrder:conditions:selectedKeys:includedKeys:limit:skip:extraOptions:tracingEnabled:] + 911
9 post 0x0000000106393d2c +[PFRESTQueryCommand findCommandParametersForQueryState:] + 296
10 post 0x00000001063937df +[PFRESTQueryCommand findCommandForQueryState:withSessionToken:] + 79
11 post 0x00000001063a5739 __78-[PFQueryController findObjectsAsyncForQueryState:withCancellationToken:user:]_block_invoke + 106
12 post 0x000000010634a7be __37+[BFTask taskFromExecutor:withBlock:]_block_invoke + 78
13 post 0x000000010634bf20 __55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2 + 112
14 libdispatch.dylib 0x000000010a2f1e5d _dispatch_call_block_and_release + 12
15 libdispatch.dylib 0x000000010a31249b _dispatch_client_callout + 8
16 libdispatch.dylib 0x000000010a2fabef _dispatch_root_queue_drain + 1829
17 libdispatch.dylib 0x000000010a2fa4c5 _dispatch_worker_thread3 + 111
18 libsystem_pthread.dylib 0x000000010a65a4f2 _pthread_wqthread + 1129
19 libsystem_pthread.dylib 0x000000010a658375 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Edit 1 :
Import UIKit
class ActivityEmployerVC: UITableViewController {
var num = 0
var postJob: String?
var dataSource: [PFObject] = []
//MARK: - PULL TO REFRESH FUNCTION
func refresh(sender:AnyObject) {
// Updating your data here...
self.fetchDataFromParse()
self.refreshControl?.endRefreshing()
}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.barTintColor = UIColor(netHex: 0x003366)
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
// Do any additional setup after loading the view.
self.refreshControl?.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
//self.refreshControl?.backgroundColor = UIColor(netHex: 0x003366)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
fetchDataFromParse()
}
//MARK: - TABLE VIEW
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let query = PFQuery(className: "Activity")
let userPointer = PFUser.objectWithoutDataWithObjectId(PFUser.currentUser()?.objectId)
query.whereKey("fromUser", equalTo: userPointer)
let objects = query.findObjects()
self.num = (objects?.count)!
print(num)
return num
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cells"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier , forIndexPath: indexPath)
if dataSource.isEmpty{
fetchDataFromParse()
print("No Post")
} else {
if num == 0{
cell.textLabel?.text = "Start posting a job!"
} else {
//MARK: - TABLEVIEW TITLE CELL
let itemArr:PFObject = self.dataSource[indexPath.row]
postJob = itemArr["type"] as? String
if postJob == "jobPost"{
let jobPostObject = PFObject(className: "JobPost")
let query = PFQuery(className: "Activity")
query.whereKey("postedJob", equalTo: jobPostObject)
let objects = query.findObjects()
print(objects)
cell.textLabel?.text = "You posted a job - \(postJob!)"
}
//MARK: - TABLEVIEW DATE CELL
let createdDate = itemArr.createdAt
let form = NSDateComponentsFormatter()
form.maximumUnitCount = 2
form.unitsStyle = .Abbreviated // or .Full, whatever you prefer
let d = form.stringFromTimeInterval(NSDate.timeIntervalSinceReferenceDate() - createdDate!.timeIntervalSinceReferenceDate)
cell.detailTextLabel?.text = "\(d!) ago"
}//end of if num
}//end of datasource.isempty
return cell
}
//MARK: - DATA FETCHING FUNCTIONS
func fetchDataFromParse() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
//MARK: - CLEARING ARRAYS
self.dataSource.removeAll()
// MARK: - JOB POST QUERY
if PFUser.currentUser()?.objectId == nil{
PFUser.currentUser()?.saveInBackgroundWithBlock({ (success, error) -> Void in
let query = PFQuery(className: "Activity")
//creating a pointer
let userPointer = PFUser.objectWithoutDataWithObjectId(PFUser.currentUser()?.objectId)
query.whereKey("fromUser", equalTo: userPointer)
query.orderByDescending("createdAt")
let objects = query.findObjects()
for object in (objects as? [PFObject])!{
//print(object.objectId)
self.dataSource.append(object)
}//end of for loop
})//end of saveInBackground
} else {
let query = PFQuery(className: "Activity")
//creating a pointer
let userPointer = PFUser.objectWithoutDataWithObjectId(PFUser.currentUser()?.objectId)
query.whereKey("fromUser", equalTo: userPointer)
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock({ (objs, error) -> Void in
if error == nil {
for obj in (objs as? [PFObject])!{
//print(object.objectId)
self.dataSource.append(obj)
self.tableView.reloadData()
}//for loop
}//end of error == nil
})// end of findobjectsinbackground
print("query executed")
}//end of PFUser objectID == nil else clause
})
}
}
EDIT 2:
This is happening because jobPostObject is not a complete object, it's just an empty, unsaved JobPost.
The query itself doesn't make a lot of sense:
You first create a new JobPost
let jobPostObject = PFObject(className: "JobPost")
Then you are trying to find an Activity associated to this JobPost:
query.whereKey("postedJob", equalTo: jobPostObject)
Since jobPostObject is brand new, has no data, and more importantly, has never been saved to parse, how could this request return anything?
That's being said this error:
Tried to save an object with a new, unsaved child
means that you are trying to use an object that is dirty in a query. A dirty object is an object that is new OR is an existing object that has been modified, but that hasn't been saved in the database.
Try to add
query.includeKey("postedJob")
after all your
let query = PFQuery(className: "Activity")
then you can replace the jobPostObject part:
let jobPostObject = PFObject(className: "JobPost")
let query = PFQuery(className: "Activity")
query.whereKey("postedJob", equalTo: jobPostObject)
let objects = query.findObjects()
print(objects)
by something like
let jobPostObject = itemArr["postedJob"] as? PFObject

EXC_BAD_ACCESS on device ONLY

So after updating xCode to version 7.1 this morning, my project suddenly crashes and throws "EXC_BAD_ACCESS (CODE = 1)" anytime I access any part of an object in a submodule but ONLY when I build on an iOS device. In simulator, I can't reproduce the issue. I've checked for zombie objects in instruments and the app just crashes without producing any warning in instruments like it would when a zombie is found. I've cloned a new version of my repo and re-added the submodule thinking maybe it had something to do with xCode itself but the issue still persists. I decided I would try to access the object in appDelegate and even there, I get the same result. Here is where the issue was originally presented:
As you can see, there is absolutely no information as to what's causing it. I move up the stack trace and everything is in assembly. Abstract User is part of a submodule but has never presented any problems until the last update. Here is the stack trace:
thread #1: tid = 0x14d13, 0x00000001011f5ad8 libswiftCore.dylibswift_initStructMetadata_UniversalStrategy + 56, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x91)
frame #0: 0x00000001011f5ad8 libswiftCore.dylibswift_initStructMetadata_UniversalStrategy + 56
frame #1: 0x0000000101162d14 libswiftCore.dylib___lldb_unnamed_function201$$libswiftCore.dylib + 84
frame #2: 0x00000001011f712c libswiftCore.dylib(anonymous namespace)::GenericCacheEntry* llvm::function_ref<(anonymous namespace)::GenericCacheEntry* ()>::callback_fn(long) + 36
frame #3: 0x00000001011f6fdc libswiftCore.dylibswift::MetadataCache<(anonymous namespace)::GenericCacheEntry>::addMetadataEntry(swift::EntryRef<(anonymous namespace)::GenericCacheEntry>, ConcurrentList<swift::MetadataCache<(anonymous namespace)::GenericCacheEntry>::EntryPair>&, llvm::function_ref<(anonymous namespace)::GenericCacheEntry* ()>) + 156
frame #4: 0x00000001011f3c50 libswiftCore.dylibswift_getGenericMetadata + 416
frame #5: 0x00000001011f3ccc libswiftCore.dylibswift_getGenericMetadata2 + 24
frame #6: 0x00000001010b1538 libswiftCore.dylibSwift._NativeDictionaryStorage.maybeGet (Swift._NativeDictionaryStorage)(A) -> Swift.Optional + 76
frame #7: 0x000000010109f4e8 libswiftCore.dylibSwift._VariantDictionaryStorage.maybeGet <A, B where A: Swift.Hashable> (Swift._VariantDictionaryStorage<A, B>)(A) -> Swift.Optional<B> + 92
frame #8: 0x000000010109f440 libswiftCore.dylibSwift.Dictionary.subscript.getter : (A) -> Swift.Optional + 168
frame #9: 0x0000000100e3d2ec ServiceKitServiceKit.ServiceModel.init (dictionary=<unavailable>, self=<unavailable>)(dictionary : Swift.Dictionary<Swift.String, Swift.AnyObject>) -> ServiceKit.ServiceModel + 316 at ServiceModel.swift:88
frame #10: 0x0000000100e1e438 ServiceKitServiceKit.AbstractUser.init (dictionary=, self=)(dictionary : Swift.Dictionary) -> ServiceKit.AbstractUser + 180 at User.swift:36
frame #11: 0x0000000100e205fc ServiceKitServiceKit.User.init (dictionary=<unavailable>, self=<unavailable>)(dictionary : Swift.Dictionary<Swift.String, Swift.AnyObject>) -> ServiceKit.User + 344 at User.swift:744
frame #12: 0x0000000100e26f48 ServiceKitServiceKit.ConsumerUser.init (dictionary=, self=)(dictionary : Swift.Dictionary) -> ServiceKit.ConsumerUser + 264 at User.swift:351
frame #13: 0x0000000100e26e34 ServiceKit`ServiceKit.ConsumerUser.__allocating_init (dictionary=, $metatype=)(dictionary : Swift.Dictionary) -> ServiceKit.ConsumerUser + 88 at User.swift:0
frame #14: 0x000000010027910c Service.comService_com.SignInViewController.signUserIn (sender=0x0000000158576b70, self=0x000000015865a760)(Service_com.MKButton) -> () + 1416 at SignInViewController.swift:62
frame #15: 0x0000000100279310 Service.com#objc Service_com.SignInViewController.signUserIn (Service_com.SignInViewController)(Service_com.MKButton) -> () + 68 at SignInViewController.swift:0
frame #16: 0x0000000189403cfc UIKit-[UIApplication sendAction:to:from:forEvent:] + 100
frame #17: 0x0000000189403c78 UIKit-[UIControl sendAction:to:forEvent:] + 80
frame #18: 0x00000001893eb930 UIKit-[UIControl _sendActionsForEvents:withEvent:] + 416
frame #19: 0x0000000189403590 UIKit-[UIControl touchesEnded:withEvent:] + 572
frame #20: 0x00000001894031c0 UIKit-[UIWindow _sendTouchesForEvent:] + 804
frame #21: 0x00000001893fbcdc UIKit-[UIWindow sendEvent:] + 784
frame #22: 0x00000001893cc4a4 UIKit-[UIApplication sendEvent:] + 248
frame #23: 0x00000001893ca76c UIKit_UIApplicationHandleEventQueue + 5528
frame #24: 0x0000000183df0544 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
frame #25: 0x0000000183deffd8 CoreFoundation__CFRunLoopDoSources0 + 540
frame #26: 0x0000000183dedcd8 CoreFoundation__CFRunLoopRun + 724
frame #27: 0x0000000183d1cca0 CoreFoundationCFRunLoopRunSpecific + 384
frame #28: 0x000000018ef58088 GraphicsServicesGSEventRunModal + 180
frame #29: 0x0000000189434ffc UIKitUIApplicationMain + 204
frame #30: 0x000000010029d09c Service.commain + 136 at AppDelegate.swift:45
frame #31: 0x000000019923a8b8 libdyld.dylibstart + 4
I've tried everything I can think of and followed numerous tutorials and debugging Bad Access errors and nothing helps. I almost feel like it's an Xcode issue but I have no idea. Here is the AbstractUser class if it helps:
public class AbstractUser: ServiceModel {
/// Date of last login
private(set) var lastLogin = NSDate()
/// Password (please, don't use this field stupidly...)
private(set) var password = String.empty
public struct SerializationKeys {
public static let lastLogin = "last_login"
public static let password = "password"
}
// MARK: - Copyable
public required init(source: Copyable) {
super.init(source: source)
let u = source as! AbstractUser
lastLogin = u.lastLogin
password = u.password
}
// MARK: - JSONSerializable
public required init(dictionary: [String : AnyObject]) {
super.init(dictionary: dictionary)
lastLogin = lastLogin <|? dictionary[SerializationKeys.lastLogin]
password = password <|? dictionary[SerializationKeys.password]
}
public override func toDictionary() -> [String : AnyObject] {
var dictionary = super.toDictionary()
dictionary[SerializationKeys.lastLogin] = lastLogin.toString()
dictionary[SerializationKeys.password] = password
return dictionary
}
// MARK: - ModelType
public override func updateObject(newVersion: ModelType) {
super.updateObject(newVersion)
let u = newVersion as! AbstractUser
lastLogin = u.lastLogin
password = u.password
}
// MARK: - NSCoding
#objc public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
lastLogin = lastLogin <|? aDecoder.decodeObjectForKey(SerializationKeys.lastLogin)
password = password <|? aDecoder.decodeObjectForKey(SerializationKeys.password)
}
#objc public override func encodeWithCoder(aCoder: NSCoder) {
super.encodeWithCoder(aCoder)
aCoder.encodeObject(lastLogin, forKey: SerializationKeys.lastLogin)
aCoder.encodeObject(password, forKey: SerializationKeys.password)
}
}
Also the User object is a subclass of AbstractUser and isn't the cause of the problem. It will produce the same error however just putting print(keys) after "let keys = ..." will cause the error just the same. The issue seems to be when I try and access any property or method on any class within that submodule.

'Tried to save an object with a new, unsaved child.' swift parse

This is my code :
userEmployer.signUpInBackgroundWithBlock { (success, error) -> Void in
if error != nil {
let errorString = error?.userInfo["error"] as! String
} else {
var queryRole = PFRole.query()
queryRole?.whereKey("name", equalTo: "Employer")
queryRole?.getFirstObjectInBackgroundWithBlock({ (roleObject, error) -> Void in
if error == nil{
var roleToAddUser = roleObject as! PFRole
roleToAddUser.users.addObject(PFUser.currentUser()!)
roleToAddUser.saveInBackground()
}// end of it
})// end of query
}//end of else
}//end of signup
It's really weird because I have the same template of code for registering a different role and it works properly. It keeps throwing
'Tried to save an object with a new, unsaved child.'
I don't understand why it's throwing an error.
First throw call stack:
(
0 CoreFoundation 0x0000000106cddf45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000106755deb objc_exception_throw + 48
2 CoreFoundation 0x0000000106cdde7d +[NSException raise:format:] + 205
3 post 0x0000000104ec93e2 -[PFPointerObjectEncoder encodeParseObject:] + 108
4 post 0x0000000104ec8874 -[PFEncoder encodeObject:] + 113
5 post 0x0000000104e97e3f __129+[PFRESTQueryCommand findCommandParametersWithOrder:conditions:selectedKeys:includedKeys:limit:skip:extraOptions:tracingEnabled:]_block_invoke97 + 1808
6 CoreFoundation 0x0000000106c4acb5 __65-[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:]_block_invoke + 85
7 CoreFoundation 0x0000000106c4abbd -[__NSDictionaryI enumerateKeysAndObjectsWithOptions:usingBlock:] + 237
8 post 0x0000000104e9764d +[PFRESTQueryCommand findCommandParametersWithOrder:conditions:selectedKeys:includedKeys:limit:skip:extraOptions:tracingEnabled:] + 911
9 post 0x0000000104e9727c +[PFRESTQueryCommand findCommandParametersForQueryState:] + 296
10 post 0x0000000104e96d2f +[PFRESTQueryCommand findCommandForQueryState:withSessionToken:] + 79
11 post 0x0000000104ea8c89 __78-[PFQueryController findObjectsAsyncForQueryState:withCancellationToken:user:]_block_invoke + 106
12 post 0x0000000104e4dd0e __37+[BFTask taskFromExecutor:withBlock:]_block_invoke + 78
13 post 0x0000000104e4f470 __55-[BFTask continueWithExecutor:block:cancellationToken:]_block_invoke_2 + 112
14 libdispatch.dylib 0x0000000108c18e5d _dispatch_call_block_and_release + 12
15 libdispatch.dylib 0x0000000108c3949b _dispatch_client_callout + 8
16 libdispatch.dylib 0x0000000108c21bef _dispatch_root_queue_drain + 1829
17 libdispatch.dylib 0x0000000108c214c5 _dispatch_worker_thread3 + 111
18 libsystem_pthread.dylib 0x0000000108f81a9d _pthread_wqthread + 729
19 libsystem_pthread.dylib 0x0000000108f7f3dd start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
added info: When I tap the register button it goes to the tableviewcontroller, I tried removing the segue and it registered the user. seems like the error is inside my tableviewconller. this is the code inside.
//creating a pointer
var userPointer = PFUser.objectWithoutDataWithObjectId(PFUser.currentUser()?.objectId)
query.whereKey("postedBy", equalTo: userPointer)
query.orderByDescending("createdAt")
if PFUser.currentUser() != nil {//added1
let objects = query.findObjects()
for object in (objects as? [PFObject])!{
//print(object.objectId)
self.dataSource.append(object)
self.createdByDate.append((object.objectForKey("closingDate") as? NSDate)!)
print(dataSource)
print(createdByDate)
}
let itemArr:PFObject = self.dataSource[indexPath.row] as! PFObject
cell?.companyPostLabel.text = (PFUser.currentUser()?.objectForKey("companyName")!.capitalizedString)! as String
cell?.occupationPostLabel.text = itemArr["occupation"]!.capitalizedString as! String
let companyImage: PFFile?
companyImage = PFUser.currentUser()?.objectForKey("profileImageEmployer") as! PFFile
companyImage?.getDataInBackgroundWithBlock({ (data, error) -> Void in
if error == nil{
cell?.companyLogoImage.image = UIImage(data: data!)
}
})
} else {
print("user not found")
}
let dateArr = createdByDate[indexPath.row]
var dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy'-'MM'-'dd' : 'hh':'mm'"
var strDate = dateFormatter.stringFromDate(dateArr)
cell?.closingDateLabel .text = strDate
edit 2 : This line is throwing the error
let query = PFQuery(className: "JobPost")
//creating a pointer
var userPointer = PFUser.objectWithoutDataWithObjectId(PFUser.currentUser()?.objectId)
query.whereKey("postedBy", equalTo: userPointer)
let objects = query.findObjects()
return (objects?.count)!
Make sure your currentUser is saved first. You can check with it's objectId.
if ([PFUser currentUser].objectId == nil)
[[PFUser currentUser] saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
// Perform queryRole
}];
else
// Perform queryRole directly

Drag & Drop Reorder Rows on NSTableView

I was just wondering if there was an easy way to set an NSTableView to allow it to reorder its rows without writing any pasteboard code. I only need it to be able to do this internally, within one table. I have no issue writing the pboard code, except that I'm fairly sure that I saw Interface Builder have a toggle for this somewhere / saw it working by default. It certainly seems like a common enough task.
Thanks
Set your table view's datasource to be a class that conforms to NSTableViewDataSource.
Put this in an appropriate place (-applicationWillFinishLaunching, -awakeFromNib, -viewDidLoad or something similar):
tableView.registerForDraggedTypes(["public.data"])
Then implement these three NSTableViewDataSource methods:
tableView:pasteboardWriterForRow:
tableView:validateDrop:proposedRow:proposedDropOperation:
tableView:acceptDrop:row:dropOperation:
Here is fully-working code that supports drag-and-drop reordering multiple rows:
func tableView(tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let item = NSPasteboardItem()
item.setString(String(row), forType: "public.data")
return item
}
func tableView(tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation {
if dropOperation == .Above {
return .Move
}
return .None
}
func tableView(tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool {
var oldIndexes = [Int]()
info.enumerateDraggingItemsWithOptions([], forView: tableView, classes: [NSPasteboardItem.self], searchOptions: [:]) {
if let str = ($0.0.item as! NSPasteboardItem).stringForType("public.data"), index = Int(str) {
oldIndexes.append(index)
}
}
var oldIndexOffset = 0
var newIndexOffset = 0
// For simplicity, the code below uses `tableView.moveRowAtIndex` to move rows around directly.
// You may want to move rows in your content array and then call `tableView.reloadData()` instead.
tableView.beginUpdates()
for oldIndex in oldIndexes {
if oldIndex < row {
tableView.moveRowAtIndex(oldIndex + oldIndexOffset, toIndex: row - 1)
--oldIndexOffset
} else {
tableView.moveRowAtIndex(oldIndex, toIndex: row + newIndexOffset)
++newIndexOffset
}
}
tableView.endUpdates()
return true
}
Swift 3 version:
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let item = NSPasteboardItem()
item.setString(String(row), forType: "private.table-row")
return item
}
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation {
if dropOperation == .above {
return .move
}
return []
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool {
var oldIndexes = [Int]()
info.enumerateDraggingItems(options: [], for: tableView, classes: [NSPasteboardItem.self], searchOptions: [:]) {
if let str = ($0.0.item as! NSPasteboardItem).string(forType: "private.table-row"), let index = Int(str) {
oldIndexes.append(index)
}
}
var oldIndexOffset = 0
var newIndexOffset = 0
// For simplicity, the code below uses `tableView.moveRowAtIndex` to move rows around directly.
// You may want to move rows in your content array and then call `tableView.reloadData()` instead.
tableView.beginUpdates()
for oldIndex in oldIndexes {
if oldIndex < row {
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
oldIndexOffset -= 1
} else {
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
newIndexOffset += 1
}
}
tableView.endUpdates()
return true
}
If you take a look at the tool tip in IB you'll see that the option you refer to
- (BOOL)allowsColumnReordering
controls, well, column reordering. I do not believe there is any other way to do this other than the standard drag-and-drop API for table views.
EDIT: ( 2012-11-25 )
The answer refers to drag-and-drop reordering of NSTableViewColumns; and while it was the accepted answer at the time. It does not appear, now nearly 3 years on, to be correct. In service of making the information useful to searchers, I'll attempt to give the more correct answer.
There is no setting that allows drag and drop reordering of NSTableView rows in Interface Builder. You need to implement certain NSTableViewDataSource methods, including:
- tableView:acceptDrop:row:dropOperation:
- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id < NSDraggingInfo >)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation
- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard
There are other SO question that address this reasonably thoroughly, including this one
Apple link to Drag and Drop APIs.
#Ethan's solution - Update Swift 4
in viewDidLoad :
private var dragDropType = NSPasteboard.PasteboardType(rawValue: "private.table-row")
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
myTableView.registerForDraggedTypes([dragDropType])
}
Later on delegate extension :
extension MyViewController: NSTableViewDelegate, NSTableViewDataSource {
// numerbOfRow and viewForTableColumn methods
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let item = NSPasteboardItem()
item.setString(String(row), forType: self.dragDropType)
return item
}
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
if dropOperation == .above {
return .move
}
return []
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
var oldIndexes = [Int]()
info.enumerateDraggingItems(options: [], for: tableView, classes: [NSPasteboardItem.self], searchOptions: [:]) { dragItem, _, _ in
if let str = (dragItem.item as! NSPasteboardItem).string(forType: self.dragDropType), let index = Int(str) {
oldIndexes.append(index)
}
}
var oldIndexOffset = 0
var newIndexOffset = 0
// For simplicity, the code below uses `tableView.moveRowAtIndex` to move rows around directly.
// You may want to move rows in your content array and then call `tableView.reloadData()` instead.
tableView.beginUpdates()
for oldIndex in oldIndexes {
if oldIndex < row {
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
oldIndexOffset -= 1
} else {
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
newIndexOffset += 1
}
}
tableView.endUpdates()
return true
}
}
Plus, for those it may concerne:
If you want to disable certain cells from being dragable, return nil in pasteboardWriterForRows method
If you want to prevent drop a certain locations ( too far for instance ) just use return [] in validateDrop's method
Do not call tableView.reloadData() synchronously inside func tableView(_ tableView:, acceptDrop info:, row:, dropOperation:). This will disturb Drag and Drop animation, and can be very confusing. Find a way to wait until animation finishes, and async it's reloading
This answer covers Swift 3, View-based NSTableViews and single/multiple rows drag&drop reorder.
There are 2 main steps which must be performed in order to achieve this:
Register table view to a specifically allowed type of object which can be dragged.
tableView.register(forDraggedTypes: ["SomeType"])
Implement 3 NSTableViewDataSource methods: writeRowsWith, validateDrop and acceptDrop.
Before drag operation has started, store IndexSet with indexes of rows which will be dragged, in the pasteboard.
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
let data = NSKeyedArchiver.archivedData(withRootObject: rowIndexes)
pboard.declareTypes(["SomeType"], owner: self)
pboard.setData(data, forType: "SomeType")
return true
}
Validate drop only if dragging operation is above of specified row. This ensures when dragging is performed other rows won't be highlighted when dragged row will float above them. Also, this fixes an AutoLayout issue.
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int,
proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation {
if dropOperation == .above {
return .move
} else {
return []
}
}
When accepting drop just retrieve IndexSet that previously was saved in the pasteboard,
iterate through it and move rows using calculated indexes.
Note: Part with iteration and row moving I've copied from #Ethan's answer.
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool {
let pasteboard = info.draggingPasteboard()
let pasteboardData = pasteboard.data(forType: "SomeType")
if let pasteboardData = pasteboardData {
if let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: pasteboardData) as? IndexSet {
var oldIndexOffset = 0
var newIndexOffset = 0
for oldIndex in rowIndexes {
if oldIndex < row {
// Dont' forget to update model
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
oldIndexOffset -= 1
} else {
// Dont' forget to update model
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
newIndexOffset += 1
}
}
}
}
return true
}
View-based NSTableViews update themselfs when moveRow is called, there is no need to use beginUpdates() and endUpdates() block.
Unfortunately you do have to write the Paste board code. The Drag and Drop API is fairly generic which makes it very flexible. However, if you just need reordering it's a bit over-the-top IMHO. But anyway, I have created a small sample project which has an NSOutlineView where you can add and remove items as well as reorder them.
This is not an NSTableView but the implementation of the Drag & Drop protocol is basically identical.
I implemented drag and Drop in one go so it's best to look at this commit.
If your are moving only one row at the time you can use the following code:
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool {
let pasteboard = info.draggingPasteboard()
guard let pasteboardData = pasteboard.data(forType: basicTableViewDragAndDropDataType) else { return false }
guard let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: pasteboardData) as? IndexSet else { return false }
guard let oldIndex = rowIndexes.first else { return false }
let newIndex = oldIndex < row ? row - 1 : row
tableView.moveRow(at: oldIndex, to: newIndex)
// Dont' forget to update model
return true
}
This is an update to #Ethan's answer for Swift 3:
let dragDropTypeId = "public.data" // or any other UTI you want/need
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let item = NSPasteboardItem()
item.setString(String(row), forType: dragDropTypeId)
return item
}
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableViewDropOperation) -> NSDragOperation {
if dropOperation == .above {
return .move
}
return []
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) -> Bool {
var oldIndexes = [Int]()
info.enumerateDraggingItems(options: [], for: tableView, classes: [NSPasteboardItem.self], searchOptions: [:]) {
if let str = ($0.0.item as! NSPasteboardItem).string(forType: self.dragDropTypeId), let index = Int(str) {
oldIndexes.append(index)
}
}
var oldIndexOffset = 0
var newIndexOffset = 0
// For simplicity, the code below uses `tableView.moveRowAtIndex` to move rows around directly.
// You may want to move rows in your content array and then call `tableView.reloadData()` instead.
tableView.beginUpdates()
for oldIndex in oldIndexes {
if oldIndex < row {
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
oldIndexOffset -= 1
} else {
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
newIndexOffset += 1
}
}
tableView.endUpdates()
self.reloadDataIntoArrayController()
return true
}
Swift 5 solution. I had to add 'registerForDraggedTypes' method in viewDidLoad for this to work.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.dataSource = self
tableView.delegate = self
// you must register the type you want to drag-n-drop! in this case 'strings'
tableView.registerForDraggedTypes([.string])
self.mapView.fitAll(in: teamManager.group.teams(), andShow: true)
}
extension ViewController : NSTableViewDataSource {
func numberOfRows(in tableView: NSTableView) -> Int {
return dataModel.count // or whatever
}
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let pasteboard = NSPasteboardItem()
// in this example I'm dragging the row index. Once dropped i'll look up the value that is moving by using this.
// remember in viewdidload I registered strings so I must set strings to pasteboard
pasteboard.setString("\(row)", forType: .string)
return pasteboard
}
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
let canDrop = (row > 2) // in this example you cannot drop on top two rows
print("valid drop \(row)? \(canDrop)")
if (canDrop) {
return .move //yes, you can drop on this row
}
else {
return [] // an empty array is the equivalent of nil or 'cannot drop'
}
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
let pastboard = info.draggingPasteboard
if let sourceRowString = pastboard.string(forType: .string) {
print("from \(sourceRowString). dropping row \(row)")
return true
}
return false
}
}
Here is the fully working code in swift 5. Lets you move multiple items at once!
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
myTableView.registerForDraggedTypes([.string])
}
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
let pasteboard = NSPasteboardItem()
pasteboard.setString("\(row)", forType: .string)
return pasteboard
}
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
return .move
}
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
var oldIndexes = [Int]()
info.enumerateDraggingItems(options: [], for: tableView, classes: [NSPasteboardItem.self], searchOptions: [:]) { dragItem, _, _ in
if let str = (dragItem.item as? NSPasteboardItem)?.string(forType: .string), let index = Int(str) {
oldIndexes.append(index)
}
}
var oldIndexOffset = 0
var newIndexOffset = 0
// For simplicity, the code below uses `tableView.moveRowAtIndex` to move rows around directly.
// You may want to move rows in your content array and then call `tableView.reloadData()` instead.
tableView.beginUpdates()
for oldIndex in oldIndexes {
if oldIndex < row {
tableView.moveRow(at: oldIndex + oldIndexOffset, to: row - 1)
oldIndexOffset -= 1
} else {
tableView.moveRow(at: oldIndex, to: row + newIndexOffset)
newIndexOffset += 1
}
}
tableView.endUpdates()
return true
}
Hope it's not too late...
I work with VisualStudio for Mac in C# and don't have Swift skills...
Can you give me a transcription in C# of this part of you'r sample?
Thank tou for helping if possible
info.enumerateDraggingItems(options: [], for: tableView, classes: [NSPasteboardItem.self], searchOptions: [:]) { dragItem, _, _ in
if let str = (dragItem.item as? NSPasteboardItem)?.string(forType: .string), let index = Int(str) {
oldIndexes.append(index)
}
}

Resources