Read array from other class in Swift - ios

I need to read an array which is in ViewController-A from ViewController-B in order to fill the data of an UIPickerView which is in ViewController-B. How could I do it ?
I have tried this answer:
https://stackoverflow.com/a/31574620/7127489
But I don't know why I can't instantiate my ViewController-B as it says in order to pass my filled array to an empty array in the other class.
Any idea ?
Thank you very much!

You can use delegates to pass data (many examples of delegation here on SO) or here
or you can do something like this:
If in navigationController:
if let navController = self.tabBarController?.viewControllers?[1] as? UINavigationController, let yourController = navController.viewControllers[0] as? yourVC{
yourArray = yourController.array
}
If not in navigationController:
if let yourController = self.tabBarController?.viewControllers?[1] as? yourVC{
yourArray = yourController.array
}

if your controller-B is seuged frome controller-A,you shuould declare a property in controller-B,and assign the value you need to controller-B when segueing.

Set up a static variable storing the array in 'ViewControllerA', then you can access it from ViewControllerB using ViewControllerA.array = [1,2,3].
You can set up the static variable as static var array = [Int]()

You would be knowing the the index of ViewControllerB in tab bar.
Declare an array in ViewControlleB. Like
var pickerData = [String]() // use appropriate type depending upon need.
Whenever the data in ViewControllerA get update update the data in ViewControllerB like this
let vcb = self.tabBarController?.viewControllers?[index of ViewControllerB] as? ViewControllerB
vcb?.pickerData = newData

Related

Accessing Data Model in UITabBarController from a Struct

I have an app that uses the UITabBarController and I have a model which I use to pass information between the various Tabs
class BaseTBController: UITabBarController {
var title: String = ""
var valueData = Double()
override func viewDidLoad() {
super.viewDidLoad()
}
Normally within any of the Tabs in the TabBars, I can just do:
let tabbar = tabBarController as! BaseTBController
let valueData = Int(tabbar.valueData) == 0 ? Int(UserDefaults.standard.double(forKey: UDKeys.valueData)) : Int(tabbar.valueData)
Now, the situation I'm in is like this, I would like to use the data from the Tabbar model data in a helper function (as struct)
Doing this, it doesn't work. Wondering if there is a way to do this and my googling/SO searching skills are just not up to par. TX
struct DataFieldOptions{
static func showValueAs() -> String {
let tabbar = tabBarController as! BaseTBController
let valueData = Int(tabbar.valueData) == 0 ? Int(UserDefaults.standard.double(forKey: UDKeys.valueData)) : Int(tabbar.valueData)
return String(valueData)
}
This seems a bit of an odd approach. If you are adding a "helper" I would expect you'd have a data-manager class rather than using a var in the tab bar controller.
However, tabBarController is an Optional property of a view controller. If you want to access it from outside the view controller you need to give it a reference.
As a side note, you're showing -> String but you're returning an Int ... I'm going to guess you're really planning on formatting the value as a string in some way, so here's how to do it returning a string:
struct DataFieldOptions{
static func showValueAs(vcRef vc: UIViewController) -> String {
// safely make sure we have access to a tabBarController
// AND that it is actually a BaseTBController
if let tbc = vc.tabBarController as? BaseTBController {
let v = Int(tbc.valueData) == 0 ? Int(UserDefaults.standard.double(forKey: UDKeys.valueData)) : Int(tbc.valueData)
return "\(v)"
}
return ""
}
}
Then, from a view controller, you would call it like this:
let str = DataFieldOptions.showValueAs(vcRef: self)

Swift: use variable for UITableViewController subclass

Take this line of code:
let controller = storyboard.instantiateInitialViewController() as! MyCustomTableViewController
Now I want to replace MyCustomTableViewController by a variable, something like this:
var customTVC: UITableViewController
customTVC = MyCustomTableViewController
let controller = storyboard.instantiateInitialViewController() as! customTVC
The compiler complains with:
Cannot assign a value of type customTVC.Type to type UITableViewController in coercion
I get the message, but what is the way to do this properly? The obvious point is that the exact sort of subclass can vary and I want to implement that controller reference only once.
If I understand your question correctly you can use typealias:
typealias customTVC = MyCustomTableViewController
let controller = storyboard.instantiateInitialViewController() as! customTVC
Take a look at the documentation here under "Type Aliases".

Cannot assign values error in swift

I am fiddling around with table views and I am stuck with the error Cannot assign a value of type 'Answer' to a value of type '[Answer]'
Answer is a class with the following definition:
class Answer {
var EnglishAnswer: String = ""
var ChineseAnswer: String = ""
init(newEng: String, newChi: String){
self.EnglishAnswer = newEng
self.ChineseAnswer = newChi
}
}
And I am running into problems in the prepareforsegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexpath: NSIndexPath = self.tableView.indexPathForSelectedRow!
var DestinationViewController = segue.destinationViewController as! AnswerTableViewController
var ArrayofArrayswithAnswerElementsTwo : Answer
var ArrayofArrayswithAnswerElements = levelsArray.map( { $0.AnswersArray })
ArrayofArrayswithAnswerElementsTwo = ArrayofArrayswithAnswerElements[indexpath.row]
DestinationViewController.ArrayofArrayswithAnswerElements = ArrayofArrayswithAnswerElementsTwo
}
Error clearly stats that you are trying to assign array of Answer objects to a variable which is declared to hold only Answer objects.
This variable is meant to hold Answer object:
var ArrayofArrayswithAnswerElementsTwo : Answer
And I suspect this line is retuning an array of Answer objects:
ArrayofArrayswithAnswerElementsTwo = ArrayofArrayswithAnswerElements[indexpath.row]
You would need to put a breakpoint, check your model, print objects and check the right assignments in your prepareForSegue function.
Solution: There could be 2 solutions to your problem:
First, define ArrayofArrayswithAnswerElementsTwo like this
var ArrayofArrayswithAnswerElementsTwo : [Answer]
Second, make ArrayofArrayswithAnswerElements[indexpath.row] to return Answer and not [Answer]
PS: Naming convention of your variables is off sync with industry practice. Variable names should start with lower case and should be kept as short as possible.

Access structure in Swift array

Can I access a struct inside of an array that is defined in the application delegate from a ViewController?
I get the error:
'Any' does not have a member named 'title' in XCode 6.2
What is the syntax for accessing a structure inside of the array?
//AppDelegate.swift
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
struct TodoItem {
var title: String
}
var todoItem = TodoItem(
title: "Get Milk")
var myArray: [Any] = []
And then in the ViewController
//
// ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let delegate = UIApplication.sharedApplication().delegate as AppDelegate
//here I'm adding the struct to the array
let myTodoItem = delegate.myArray.append(delegate.todoItem)
//how do I access the items in the struct?
println(delegate.myArray[0].title)
You can access structures in array same as you would classes.
Your issue is that you explicitly tell that the array contains Any Objects. Type the array to be of type MyStruct and it works fine:
var myArray: [MyStructure] = [];
alternatively, if you can't modify the array declaration, cast:
myValueIWannaRead = (myArray[0] as MyStruct).myValueIWannaRead
You can define the array to store the type you desire :
var myArray: [TodoItem] = [];
Then you can access the instances properly.
The Any type denotes an object of an unknown type (class/primitive type ) and during compilation time there is no way to know which type the instance accessed will be of.
In Swift be always as specific as possible.
If the array contains only items of type TodoItem, declare it respectively.
var myArray: [TodoItem] = []
Any is a kind of placeholder, the compiler has no idea what dynamic type it is.
Why do you have to add the struct TodoItem to AppDelegate? in my point of view, it would be better to create it in the same file that you have your view controller or - even better - create a new Swift file named TodoItem.swift holding the struct.
Then after you have moved your struct to a new file or inside your View Controller file, but outside your ViewController class. You can just call:
let myTodoItem = TodoItem(title: "Get Milk") // declaring TodoItem
var myTodoItemArray : [TodoItem] = [] // declaring TodoItem array
myTodoItemArray.append(myTodoItem) // Appending to the array
// then you can set it by calling the array only member
let todoItem = myTodoItemArray[0] as! TodoItem
let title = todoItem.title
// Or you can just call the toDo Item itself
let title = myTodoItem.title
If you want to comunicate this data between two different classes, I would suggest use Delegation by creating a protocol or Notifications with NSNotifications.
I hopw this helps, happy coding.
EDIT: Fixed some minor error in the code
Solution1: Your struct is defined under AppDelegate class so, you will have to parse it like this;
//** Swift 1.2, xCode 6.3.1**//
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
//here I'm adding the struct to the array
delegate.myArray.append(delegate.todoItem)
//how do I access the items in the struct?
println((delegate.myArray[0] as! AppDelegate.TodoItem).title)
Solution2: Change the data type of your array Any to TodoItem
var myArray: [TodoItem] = []
and then, it would work;
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
//here I'm adding the struct to the array
delegate.myArray.append(delegate.todoItem)
//how do I access the items in the struct?
println(delegate.myArray[0].title)

Implementing a UISearchController in Swift Core Data Project

I'm presently taking an iOS development course. As part of an assignment, I'm tasked with creating a UISearchController in a note tracking project using Core Data in Swift.
Every example I've found is in Objective-C or is filtering a static array. Apple's "sample" code, updated in December 2014 doesn't compile in Xcode 6.3.
To add a UISearchController, I've got 3 primary tasks to do:
1) Create a view controller to present search results. I'm using a TableViewController.
2) Create a UISearchController, and pass it my search results view controller.
What's "stumping" me is now to get a hold of the objects in the managedObjectsContext. Prior to attempting to add a UISearchController, my app works fine. I can add, edit, and delete items. I'm using the "canned" Core Data code in Xcode 6.3 with the stack in AppDelegate.
class MasterViewController: UITableViewController, NSFetchedResultsControllerDelegate
var searchController: UISearchController? = nil
func addSearchBar() {
var resultsController = SearchResultsTableViewController()
resultsController.notes = // stumped what to call the notes. Trying to call an array from the Notes class below
resultsController.delegate = self
searchController = UISearchController(searchResultsController: resultsController)
searchController!.searchResultsUpdater = resultsController
searchController!.searchBar.frame = CGRect(
x: searchController!.searchBar.frame.origin.x,
y: searchController!.searchBar.frame.origin.y, width: searchController!.searchBar.frame.size.width, height: 44.0)
tableView.tableHeaderView = searchController!.searchBar
self.definesPresentationContext = true
}
3) The UISearchController will notify its searchResultsUpdater (a class that conforms to UISearchResultsUpdating) when the search text changes. I'm using my search results view controller implement this protocol so I can update the filtered results.
Below is my Note: NSManagedObject class:
import Foundation
import CoreData
class Note: NSManagedObject {
#NSManaged var dateCreated: NSDate
#NSManaged var dateEdited: NSDate
#NSManaged var noteTitle: String
#NSManaged var noteBody: String
// TODO: adding this to make it easier to handle names
class func notes() -> NSArray {
let whereMyNotesAreStored = // Need syntax for where my MyManagedObjectContext is located
let dataArray = NSArray(contentsOfFile: whereMyNotesAreStored!)
var notesArray = NSMutableArray()
for dictionary in dataArray {
var note = Note()
note.noteTitle = dictionary["noteTitle"] as! String
note.noteBody = dictionary["noteBody"] as! String
note.dateCreated = dictionary["dateCreated"] as! String
note.dateEdited = dictionary["dateEdited"] as! String
notesArray.addObject(note)
}
return NSArray(array: notesArray as! [AnyObject])
}
}
There are two approaches to setting the context:
Calling back to the App Delegate:, like this
let appDelegate : AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context = appDelegate.managedObjectContext!
or passing the context forward from the App Delegate to the Master View Controller, which then passes it on to any subsequent view controllers, etc. Each view controller will need a property defined for the context; when a new VC is instantiated, the context is set before the VC is presented/pushed, eg:
class CustomViewController : UIViewController {
var managedObjectContext : NSManagedObjectContext
...
and, when loading a new view controller,
let newVC = CustomViewController()
newVC.managedObjectContext = self.managedObjectContext
...
To access the objects, use either a NSFetchRequest or NSFetchedResultsController to create an array of results, which you can then pass to the resultsController. eg. for a fetch request:
let fetch = NSFetchRequest(entityName: "Notes")
var error : NSError? = nil
let fetchedResults = managedObjectContext?.executeFetchRequest(fetch, error: &error)
(Your notes() function is on the wrong track - you would not use NSArray(contentsOfFile:) to access CoreData objects. Also, you must use the designated initialiser for NSManagedObject subclasses: so not var note = Notes() but var note = Notes(entity: NSEntityDescription, insertIntoManagedObjectContext: NSManagedObjectContext?)

Resources