String use on another class - string

I want to user sting in another class so if you know how to use? please help me.
I am using below link but it did't work for me. it return nil or fatal error.
How to call another method from another class in swift?
below code:
var objSymbol = SymbolListVC()
code = objSymbol.code
selectedMarket = objSymbol.SMarket
below Code of Symbol class:I am gating the value in code and skt
var Skt: String!
var code: String!
code = sbol?["Code"] as? String
Skt = sbol?["kt"] as? String
Thank You.

Does SymbolListVC.code have an initial value? Or do you mean to use an existing object of SymbolListVC and read the value of code from there?
Ideally, you should be using if directives if you are not certain that a variable will have a value
if let code = objSymbol.code {
//Do your processing here
}
But before that, assuming you want to use an existing instance of SymbolListVC, your code will create a new object of the class. So you might want to change that part.

var valueToPass:String!
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
println("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow();
let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!;
valueToPass = currentCell.textLabel.text
performSegueWithIdentifier("yourSegueIdentifer", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "yourSegueIdentifer") {
// initialize new view controller and cast it as your view controller
var viewController = segue.destinationViewController as AnotherViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
}
}

Related

Action when user click on the delete button on the keyboard in SwiftUI

I try to run a function when the user click on the delete button on the keyboard when he try to modify a Textfield.
How can I do that ?
Yes it is possible, however it requires subclassing UITextField and creating your own UIViewRepresentable
This answer is based on the fantastic work done by Costantino Pistagna in his medium article but we need to do a little more work.
Firstly we need to create our subclass of UITextField, this should also conform to the UITextFieldDelegate protocol.
class WrappableTextField: UITextField, UITextFieldDelegate {
var textFieldChangedHandler: ((String)->Void)?
var onCommitHandler: (()->Void)?
var deleteHandler: (() -> Void)?
override func deleteBackward() {
super.deleteBackward()
deleteHandler?()
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = textField.superview?.superview?.viewWithTag(textField.tag + 1) as? UITextField {
nextField.becomeFirstResponder()
} else {
textField.resignFirstResponder()
}
return false
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let currentValue = textField.text as NSString? {
let proposedValue = currentValue.replacingCharacters(in: range, with: string)
textFieldChangedHandler?(proposedValue as String)
}
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
onCommitHandler?()
}
}
Because we are creating our own implementation of a TextField we need three functions that we can use for callbacks.
textFieldChangeHandler this will be called when the text property updates and allows us to change the state value associated with our Textfield.
onCommitHandler this will be called when we have finished editing our TextField
deleteHandler this will be called when we perform he delete action.
The code above shows how these are used. The part that you are particularly interested in is the override func deleteBackward(), by overriding this we are able to hook into when the delete button is pressed and perform an action on it. Depending on your use case, you may want the deleteHandler to be called before you call the super.
Next we need to create our UIViewRepresentable.
struct MyTextField: UIViewRepresentable {
private let tmpView = WrappableTextField()
//var exposed to SwiftUI object init
var tag:Int = 0
var placeholder:String?
var changeHandler:((String)->Void)?
var onCommitHandler:(()->Void)?
var deleteHandler: (()->Void)?
func makeUIView(context: UIViewRepresentableContext<MyTextField>) -> WrappableTextField {
tmpView.tag = tag
tmpView.delegate = tmpView
tmpView.placeholder = placeholder
tmpView.onCommitHandler = onCommitHandler
tmpView.textFieldChangedHandler = changeHandler
tmpView.deleteHandler = deleteHandler
return tmpView
}
func updateUIView(_ uiView: WrappableTextField, context: UIViewRepresentableContext<MyTextField>) {
uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
}
}
This is where we create our SwiftUI version of our WrappableTextField. We create our WrappableTextField and its properties. In the makeUIView function we assign these properties. Finally in the updateUIView we set the content hugging properties, but you may choose not to do that, it really depends on your use case.
Finally we can create a small working example.
struct ContentView: View {
#State var text = ""
var body: some View {
MyTextField(tag: 0, placeholder: "Enter your name here", changeHandler: { text in
// update the state's value of text
self.text = text
}, onCommitHandler: {
// do something when the editing finishes
print("Editing ended")
}, deleteHandler: {
// do something here when you press delete
print("Delete pressed")
})
}
}

tableView didSelectRowAt indexPath not firing the first time the view loads, works great the second time

I have a tableView in a View Controller with delegate and datasource wired up through the IB. I'm using the tableView for multi selection. In my didSelectRowAt IndexPath, selection lets the user mark a relationship between two Core Data entities:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let wageClassObject = self.wageClasses[indexPath.row]
let wageClassStatus = wageClassObject.value(forKey: "checked") as? Bool
wageClassObject.setValue(!wageClassStatus!, forKey:"checked")
if (wageClassStatus)! {
proposalToEdit?.addToWageClasses(wageClassObject)
}
else {
proposalToEdit?.removeFromWageClasses(wageClassObject)
}
}
When the user loads the view the first time, selecting a row has no effect. When the user loads the view the second time, the add and remove functions work great.
I've tried every solution suggested in this thread but no dice. I can't find a case quite like mine, either, where the issue is that it doesn't work the first time the view loads.
Suggestions greatly appreciated!
Edited to add: viewDidLoad and Core Data code
override func viewDidLoad() {
loadProposalData()
tableView.reloadData()
super.viewDidLoad()
proposalNameField.delegate = self
pensionField.delegate = self
percentField.delegate = self
if let topItem = self.navigationController?.navigationBar.topItem {
topItem.backBarButtonItem = UIBarButtonItem(title: "", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
}
if wageClasses != nil {
getWageClasses()
print("\(wageClasses)")
}
}
func getWageClasses(){
let fetchRequest: NSFetchRequest<WageClass> = WageClass.fetchRequest()
do {
try self.wageClasses = context.fetch(fetchRequest)
} catch {
// handle error
}
}
#IBAction func calculateButtonTapped(_ sender: UIButton) {
var proposal: Proposal!
if proposalToEdit == nil {
proposal = Proposal(context: context)
} else {
proposal = proposalToEdit
}
proposal.dateCreated = currentDateTime as NSDate?
if let proposalName = proposalNameField.text {
proposal.proposalName = proposalName
}
if let pensionContribution = pensionField.text {
proposal.pensionContribution = (pensionContribution as NSString).doubleValue
}
if let percentIncrease = percentField.text {
proposal.percentIncrease = (percentIncrease as NSString).doubleValue
}
/// if let setting the checked value?
adD.saveContext()
_ = navigationController?.popViewController(animated: true)
}
I am not using viewDidAppear.
A little more about the Core Data. I have two entities, proposal and wageClass. Both have a to-many relationship to each other. On this viewController, the user can edit the proposal through three textfields (name, percent increase, pension amount) and then select related wageClasses from the tableView.
I want the user to be able to input the proposal fields and select the related wageClasses the first time they click the Add button in the nav bar on the previous viewController. What's happening is that the user clicks add, inputs the data to the text fields, selects the wage classes, and hits calculate. The text fields save and the labels update with the programmed calculations, but the wageClasses data remain nil. If the user selects the proposal again (that's what I mean by loads the view a second time above) then the user can add the wageClasses and all the calculations run correctly. But not before that second opening of the view.
screenshot of the view
You code uses proposalToEdit instance variable:
if (wageClassStatus)! {
proposalToEdit?.addToWageClasses(wageClassObject)
}
else {
proposalToEdit?.removeFromWageClasses(wageClassObject)
}
Which is basically nil here, it must be initialized before calling this functions, thus making this calls not executed (can't be done on nil object). You insert it to the context for the first time in calculateButtonTapped:
if proposalToEdit == nil {
proposal = Proposal(context: context)
}
if you want it to work first time (i.e. before first click on 'calculate'), add above code somewhere in viewDidLoad, like this:
override func viewDidLoad() {
loadProposalData()
if proposalToEdit == nil {
proposal = Proposal(context: context)
}
If above doesn't work I suggest you add a link to the repository to help debug this code, I cannot find more flaws in here, but there are no details in add and remove implementations, as well as how your core data stack works.
If anyone is stuck on the same problem, the key is to create the core data object before you add a relationship to another object. The above code doesn't work because I was trying to add relationships to objects that didn't yet exist.
My solution was to separate the operations in two view controllers but I would love to know more about how such can be achieved in one view controller.

leak memory with performSegue with identifier in swift 3

please i have an problem with perform segue with identifier in table view didSelectRow method every time i tapped the cell the memory is increasing
the following is my code :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// firstly i need to check if edit button is true so i can select cell
if isShowToolBar {
// her for hold selected index
let cell = tableView.cellForRow(at: indexPath) as? MovieDownloadedTableViewCell
if let cell = cell {
cell.movieCheckMarkImageView.isHidden = false
cell.movieEmptyCircleImageView.isHidden = true
operationDocumentDirectoryObject.dictionaryHoldIndexCellForDisplayWhichCellSelected.updateValue(indexPath.row, forKey: indexPath.row)
// start hold URL
operationDocumentDirectoryObject.dictionaryForHoldURLSelected.updateValue(operationDocumentDirectoryObject.arrayOfMovieURL![indexPath.row], forKey: indexPath.row)
}// end the if let cell
}else{
// her for show the content folder
let cell = tableView.cellForRow(at: indexPath) as? MovieDownloadedTableViewCell
if let cell = cell {
if cell.fetchURL!.pathExtension == "" {
performSegue(withIdentifier: "ShowFolder", sender: indexPath.row)
}else{
// playing the video
performSegue(withIdentifier: "PlayingMovie", sender: cell.fetchURL!.lastPathComponent)
}// end the if for check path extenstion
}// end the if let cell
cell = nil
}// end the if for the isShowToolbar
}
the above method have memory leak in perform segue and cause increasing memory with the (if cell.fetchURL!.pathExtension == "") also make memory leak
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MoveFile" {
if let destination = segue.destination as? MoveMovieViewController {
destination.operationDocumentDirectoryObject.dictionaryForHoldURLSelected = self.operationDocumentDirectoryObject.dictionaryForHoldURLSelected
}
}else if segue.identifier == "ShowFolder" {
if let destination = segue.destination as? ShowContentFolderMovieViewController {
if let fetchIndex = sender as? Int {
destination.operationDocumentDirectory.folderName = self.operationDocumentDirectoryObject.arrayOfMovieURL![fetchIndex].lastPathComponent
}
}
}else if segue.identifier == "PlayingMovie" {
// make an object for the playing video view controller
if let destination = segue.destination as? PlayingMovieViewController {
if let movieName = sender as? String {
destination.operationDocumentDirectory.movieName = movieName
}
}
}// end the condition for the segue
}
although the deinit is call success in the view controller but i have still leaking and increasing memory
please help for what is my wrong code?
thank you very much
I suspect you have a strong reference cycle somewhere in your code - although, not in the bit that you have posted as far as I can tell. However, you say that your deinit is being called successfully. Did you check to see if the deinits of all of the view controllers you are segueing to are being called at the expected time (such as when you dismiss PlayingMovieViewController or ShowContentFolderMovieViewController)? Observing the xcode debug console for deinit print statements to check for the appropriate releases in memory is the best way to go. Your memory leak could be coming from somewhere else though. You should look out for strong references elsewhere in your code (maybe a delegate holding on to sender objects?).

How to implement finding all positions of one string in another string at the time of typing the string where to search for?

I would like to have the following functionality in my app:
When I type the DNA sequence (string) in the NSTextView window at the same time in my TableView for each enzyme (each of them representing small string) user immediately see the number of found sites (string) corresponding to each enzyme (0 or any number).
I have a function, which I can use to find all possible locations (returning NSRanges array) of string in string. In my case this will be to find in DNA sequence (string) all possible sites (strings NSRanges) corresponding for each enzyme.
Thus, one more time, question is how to implement this function: at the time of typing a string to find all sites (in form of array of NSRanges) in this string and put the numbers found site in table accordingly for each enzyme.
In other words, the function returning NSRanges array for positions of enzymes sites should start automatically.
Update
I am new in cocoa and after suggestions from R Menke (I have putted his code lines below in the code) I have more probably stupid questions. I have one controller class as subclass of NSWindowController. I cannot put code from R Menke to this class (see errors below). And, in my controller class I have my NSTextView where user will type the text as #IBOutlet, should I use this? Should I make another controller file ? Below the code and errors.
import Cocoa
//Error. Multiple inheritance from classes 'NSWindowController' and 'NSViewController'
class AllUnderControl: NSWindowController, NSViewController,NSTextViewDelegate
{
override var windowNibName: String?
{
return "AllUnderControl"
}
override func windowDidLoad() {
super.windowDidLoad()
}
//Error. Instance member 'inputDnaFromUser' cannot be used on type 'AllUnderControl'
var textView = inputDnaFromUser(frame: CGRectZero)
//Error. Method does not override any method from its superclass
override func viewDidLoad() {
textView.delegate = self
}
func textDidChange(notification: NSNotification) {
// trigger your function
}
#IBOutlet var inputDnaFromUser: NSTextView!
Update 2
After reading the description of two controllers: NSWindowController and NSViewController I have made the following changes below. Is it correct for triggering function ?
import Cocoa
class AllUnderControl: NSWindowController, NSTextViewDelegate
{
override var windowNibName: String?
{
return "AllUnderControl"
}
override func windowDidLoad() {
super.windowDidLoad()
inputDnaFromUser.delegate = self
}
func textDidChange(notification: NSNotification) {
// trigger your function
}
#IBOutlet var inputDnaFromUser: NSTextView! = NSTextView(frame: CGRectZero)
If you are asking: "how do I trigger a function when someone types in an NSTextView?"
Implement an NSTextViewDelegate set the delegate of your NSTextView to self and trigger your function inside textDidChange. The NSTextViewDelegate has a set of functions that will be triggered by user interaction. So code inside of them will be executed when the corresponding action happens.
I would suggest using an NSViewController for this and not an NSWindowController. A NSWindowController is used to manage NSViewControllers. NSViewControllers are a better place for things like buttons and textfields.
NSWindowController vs NSViewController
class ViewController: NSViewController, NSTextViewDelegate {
#IBOutlet var inputDnaFromUser: NSTextView!
override func viewDidLoad() {
super.viewDidLoad()
inputDnaFromUser.delegate = self
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
func textDidChange(notification: NSNotification) {
print("editing stuff")
}
}
If you are asking: "how can I find all occurrences of a string in another string?"
This will return an array of ranges. The count of that array is obviously the number of occurrences.
Another option is to use enumerateSubstringsInRange as stated in the answer by #Russel. I just always preferred to write my own loop.
let string = "The sky is blue today, super blue"
let searchString = "blue"
var ranges: [NSRange] = []
var copyString = NSMutableString(string: string)
while copyString.containsString(searchString) {
ranges.append(copyString.rangeOfString(searchString))
guard let lastRange = ranges.last else {
break
}
var replaceString = ""
for _ in 0..<lastRange.length { replaceString += "$" } // unnalowed character
copyString.replaceCharactersInRange(lastRange, withString: replaceString)
}
As suggested in the comments:
A faster method.
let string : NSString = "The sky is blue today, super blue"
let searchString = "blue"
var ranges: [NSRange] = []
var searchRange : NSRange = NSRange(location: 0, length: string.length)
var lastFoundRange : NSRange = string.rangeOfString(searchString, options: NSStringCompareOptions.LiteralSearch, range: searchRange)
while lastFoundRange.location != NSNotFound {
ranges.append(lastFoundRange)
let searchRangeLocation = lastFoundRange.location + lastFoundRange.length
let searchRangeLength = string.length - searchRangeLocation
searchRange = NSRange(location: searchRangeLocation, length: searchRangeLength)
lastFoundRange = string.rangeOfString(searchString, options: NSStringCompareOptions.LiteralSearch, range: searchRange)
}
You will be wanting to do this on a background queue. But this gets tricky quickly. An enzyme can be one kind one moment and change the next. So you will need to do all the work with every character typed.
One possible solution is to cancel each ongoing search when a character is typed. If it finished before typing the next character you get results.
This is an iOS word highlighter I wrote that implements this logic. Except for the use of UIColor everything is pure Foundation. So easy to change it to Cocoa.
You will want to implement the UISearchResultsUpdating protocol to achieve this. It uses a UISearchController (introduced in iOS 8) which has to be added programmatically instead of through the storyboard, but don't worry, it's pretty straight-forward.
The searching is handled using the updateSearchResultsForSearchController delegate method which is called anytime the search bar text is changed. I tried to keep it pretty self-documenting but let me know if you have any questions. Depending on how many enzymes you care to search, this could get inefficient very quickly because you have to search for substring occurrences for each enzyme.
Cheers,
Russell
class YourTableViewController: UITableViewController, UISearchBarDelegate, UISearchResultsUpdating {
// Array of searchable enzymes
var enzymes: [String] = ["...", "...", "..."]
// Dictionary of enzymes mapping to an array of NSRange
var enzymeSites: [String : [NSRange]] = [String : [NSRange]]()
// Search controller
var enzymeSearchController = UISearchController()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.enzymeSearchController = UISearchController(searchResultsController: nil)
self.enzymeSearchController.dimsBackgroundDuringPresentation = true
// This is used for dynamic search results updating while the user types
// Requires UISearchResultsUpdating delegate
self.enzymeSearchController.searchResultsUpdater = self
// Configure the search controller's search bar
self.enzymeSearchController.searchBar.placeholder = "Enter DNA sequence"
self.enzymeSearchController.searchBar.sizeToFit()
self.enzymeSearchController.searchBar.delegate = self
self.definesPresentationContext = true
// Set the search controller to the header of the table
self.tableView.tableHeaderView = self.enzymeSearchController.searchBar
}
// MARK: - Search Logic
func searchEnzymeSites(searchString: String) {
// Search through all of the enzymes
for enzyme in enzymes {
// See logic from here: https://stackoverflow.com/questions/27040924/nsrange-from-swift-range
let nsEnzyme = searchString as NSString
let enzymeRange = NSMakeRange(0, nsEnzyme.length)
nsEnzyme.enumerateSubstringsInRange(enzymeRange, options: NSStringEnumerationOptions.ByWords, { (substring, substringRange, enclosingRange, stop) -> () in
if (substring == enzyme) {
// Update the enzymeSites dictionary by appending to the range array
enzymeSites[enzyme]?.append(substringRange)
}
})
}
}
// MARK: - Search Bar Delegate Methods
func searchBarSearchButtonClicked(searchBar: UISearchBar) {
// Force search if user pushes button
let searchString: String = searchBar.text.lowercaseString
if (searchString != "") {
searchEnzymeSites(searchString)
}
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
// Clear any search criteria
searchBar.text = ""
// Force reload of table data from normal data source
}
// MARK: - UISearchResultsUpdating Methods
// This function is used along with UISearchResultsUpdating for dynamic search results processing
// Called anytime the search bar text is changed
func updateSearchResultsForSearchController(searchController: UISearchController) {
let searchString: String = searchController.searchBar.text.lowercaseString
if (searchString != "") {
searchEnzymeSites(searchString)
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (self.enzymeSearchController.active) {
return self.enzymeSites.count
} else {
// return whatever your normal data source is
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("userCell") as! UserCell
if (self.enzymeSearchController.active && self.enzymeSites.count > indexPath.row) {
// bind data to the enzymeSites cell
} else {
// bind data from your normal data source
}
return cell
}
// MARK: - UITableViewDelegate
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if (self.enzymeSearchController.active && self.searchUsers.count > 0) {
// Segue or whatever you want
} else {
// normal data source selection
}
}
}

Store Integers in Core Data using Swift and XCode

While Strings appears to be fine I'm having some trouble storing Integers into Core Data. Following tutorials and reading available information out there doesn't seem to be helping me who has no Objective-C background. (Swift seemed like a straight forward language like the languages I'm fluent with PHP/OOPHP/JavaScript/VBScript/... thus I started playing with it and so far have been able to do everything I wanted, almost)
What I want to do now is, to receive the JSON data and store it into Core Data
Here's my Core Data
Entity name: Category
Its Attributes:
id Int16
title String
description String
My Swift model? file: Category.swift
import CoreData
class Category: NSManagedObject {
#NSManaged var id: Int //should I declare this as Int16?
#NSManaged var title: String
#NSManaged var description: String
}
I'm using SwiftyJASON extension? and NSURLSession protocol? to get the data and to parse it as follow:
import UIKit
import CoreData
class ViewController: UIViewController {
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
func fetchData() {
var url = NSURL.URLWithString("http://domain.com/index.php?r=appsync/read&id=category")
var session = NSURLSession.sharedSession()
session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
// parse data into json
let json = JSONValue(data)
let entityDescription = NSEntityDescription.entityForName("Category", inManagedObjectContext: self.managedObjectContext)
let category = Category(entity: entityDescription, insertIntoManagedObjectContext: self.managedObjectContext)
for item in json.array! {
category.id = item["id"].string!.toInt()! //goes KABOOM!
category.title = item["title"].string!
category.description = item["description"].string!
managedObjectContext?.save(nil)
}
dispatch_async(dispatch_get_main_queue()) {
// do something
}
}).resume()
}
}
Let's assume the JASON data is:
[{"id":"1","title":"cat1","description":"blabala one"},{"id":"2","title":"cat2","description":"blabala two"}]
At line where it says category.id = item["id"].string!.toInt()! xCode goes KABOOM, what am I doing wrong here?
Notes/More questions:
I tried changing id type within Core Data to Int32 and then declaring it as just Int
in the model (and not Int16 or Int32) which reduced some errors but
xCode still crashes
Probably the way I'm looping stuff is not the best way to do this,
what's the better way of storing array of data into core data at
once?
Most of the tutorials I've seen there's no id's for Entities(tables), am I missing something here?
References:
SiftyJSON: https://github.com/lingoer/SwiftyJSON
Core Data tutorial:
http://rshankar.com/coredata-tutoiral-in-swift-using-nsfetchedresultcontroller/
EDIT > Working code:
Category.swift model file which can be auto generated using File>New>File>iOS>Core Data>NSManagedObject subclass [swift, no need for bridging header but you need to manually add #objc line as below]
import CoreData
#objc(Category) //Wouldn't work without this
class Category: NSManagedObject {
#NSManaged var id: NSNumber //has to be NSNumber
#NSManaged var title: String
#NSManaged var mydescription: String //"description" is reserved so is "class"
}
ViewController.swift
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
}
func fetchData() {
var url = NSURL.URLWithString("http://domain.com/index.php?r=appsync/read&id=category")
var session = NSURLSession.sharedSession()
session.dataTaskWithURL(url, completionHandler: {(data, response, error) in
let json = JSONValue(data)
let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext //this line had to be moved here
let entityDescription = NSEntityDescription.entityForName("Category", inManagedObjectContext: managedObjectContext)
for item in json.array! {
let category = Category(entity: entityDescription, insertIntoManagedObjectContext: managedObjectContext) //this line has to be in inside for loop
category.id = item["id"].string!.toInt()!
category.title = item["title"].string!
category.mydescription = item["description"].string!
managedObjectContext?.save(nil)
}
dispatch_async(dispatch_get_main_queue()) {
// do something
}
}).resume()
}
}
Sample fetching data code:
func requestData() {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Category")
request.returnsObjectsAsFaults = false
var results:NSArray = context.executeFetchRequest(request, error: nil)
//println(results)
for category in results {
var cat = category as Category
println("\(cat.id),\(cat.title),\(cat.mydescription)")
}
}
P.S. Make sure to Clean your project and delete the app from simulator after changing Model
Scalar types (integers, floats, booleans) in core data are broken in the current Swift beta (5). Use NSNumber for the properties, and file a radar.
object.intProperty = NSNumber(int:Int(item["id"] as String))
(Typed on the phone, so sorry if that's wrong, and I know it's disgusting code - hence, file a radar!)
Or, in your specific case, looking at the JSON, use String. Those IDs are coming in as strings anyway.
Updated for Swift 2
If your JSON data is really of type [[String:String]], you can use the following code in order to set category.id:
if let unwrappedString = item["id"], unwrappedInt = Int(unwrappedString) {
category.id = unwrappedInt
}

Resources