Swift: EXC_BAD_ACCESS when I access class property - swift2

EXC_BAD_ACCESS occurs when I access (read or rewrite) property of class instance.
class MyUIImageView:UIImageView {
required init?(coder aDecoder: NSCoder) {
fatalError()
}
var hand: String = ""
}
#IBOutlet weak var myInstance: MyUIImageView!
func rewrite() {
...
myInstance.hand = "..." // Error!
}
func read() {
...
var tmp: String = myInstance.hand // Error!
}
Do you know how to fix this error?
・2016/1/31
Unknown class MyUIImageView in Interface Builder was found in log, and Module field of Custom Class is "None".

either myInstance isn't set or myInstance isn't a MyUIImageView

Related

How set initial values for stored property with initializers?

This code doesn't work.
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var textField: NSTextField!
var guessScore : Int
override func viewDidLoad() {
super.viewDidLoad()
}
override init(){
super.init()
guessScore = 1
}
before calling super.init(), all your properties must be initialized (they have to have some 'default' value), Please read apple docs.
override init(){
guessScore = 1
super.init()
}
Your code produces:
So you may want to simply follow the instructions given by Xcode and override the designated initializer:
var guessScore: Int
override init?(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
guessScore = 1
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
required init?(coder: NSCoder) {
guessScore = 1
super.init(coder: coder)
}
Or directly without any initializer, provide a default value:
var guessScore: Int = 1

Initialising UIViewController subclass error

I am learning Swift and I have a compile error:
class ListScansVC: UIViewController {
#IBOutlet weak var tableView: UITableView!
internal var scans: [Scan]
internal var dataSource: ListScanDataSource
init(scans: [Scan]){
self.scans = scans
dataSource = ListScanDataSource.init(scans: scans)
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
dataSource.registerReusableViewsForTableView(tableView)
}
}
In another ViewController i am doing:
override func viewDidLoad() {
super.viewDidLoad()
let scan = Scan(title : "Ticket", scanDate: NSDate())
let listScanVC = ListScansVC.init(scans: [scan])
self.displayChildContent(ListScansVC)
}
func displayChildContent(content : UIViewController){
self.addChildViewController(content)
self.view.addSubview(content.view)
content.didMoveToParentViewController(self)
}
The error is:
"Cannot convert value of Type 'ListScansVC.Type' to expected argument type 'UIViewController'"
An init method in Swift like
init(scans :[Scan]){)
has be be called with
let listScanVC = ListScansVC(scans: [scan])
in the next line you have to pass the instance (starting with a lowercase letter) rather than the type
self.displayChildContent(listScanVC)
I'd recommended to use more distinctive names to avoid that type/instance confusion.

Swift - Pass a reference to a class

I have a class which will perform a search. Once complete I want the search class to pass back the results to which ever instance (of another class) started the search. My thinking was to pass a reference to the class which instantiates the search class and use that reference to call a function. Here's a basic example of what I'm trying to do. How can I get this to work, or is there another/better way?
Search Class (I've tried AnyObject and UITableViewContoller):
class SearchClass : NSObject, NSURLConnectionDelegate, NSURLConnectionDataDelegate {
var callingClass : AnyObject? = nil //To store reference to the "other" class
var searchResults : [[String : AnyObject]]? = nil
init(callingClass: AnyObject) { //I don't know the name of the ViewController class which will instantiates this as it will be called by several different classes
self.callingClass = callingClass
}
func startSearch(searchString: String) {
//NSURLConnection etc
}
func connectionDidFinishLoading(connection: NSURLConnection) {
//more code
searchResults = ...
callingClass!.searchCompleted(searchResults) //Pass the search results back to the class instance which started the search
}
}
Other Classes:
class RandomViewController : UITableViewController {
//The casting on the next line fails
let Searcher = SearchClass(callingClass: self as! UITableViewController) //OR AnyObject
func randomFunction() {
searcher.startSearch("search query")
}
func searchComplete(searchResults: [[String : AnyObject]]) {
self.searchResults = searchResults
tableView.reloadData()
}
}
You can add a closure parameter to your startSearch function in your search class:
typealias SearchResultHandler = (result: [String : AnyObject]) -> ()
func startSearch(query: String, resultHandler: SearchResultHandler) {
// send the search request and in the completion handler of the request call your result handler:
resultHandler(result: searchResult)
}
Which you would then call from any class:
let searcher = SearchClass()
searcher.startSearch("query") { (result) -> () in
self.searchResults = results
tableView.reloadData()
}
You can use generics when you don't know what the class is going to be:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Generics.html
However....
This seems like something that you should use protocol / delegates for.
// NOTE: weak references must be class type
protocol SearchClassDelegate: class {
func searchComplete(results: [[String: AnyObject]?])
}
// This is where you define T as the generic class
class SearchClass {
weak var delegate: SearchClassDelegate? // This is your "callingClass"
// NOTE: make sure it's weak
// ...
func connectionDidFinishLoading() {
// ...
self.delegate?.searchComplete(results)
}
}
// Set to the delegate
class ViewController: UIViewController, SearchClassDelegate {
// ...
// Make sure you set the delegate
// Here is where you implement this function
func searchComplete(results: [[String : AnyObject]?]) {
// Do whatever
// ...reloadData() etc.
}
}

How to unarchive custom array with NSUserDefaults?

I'm saving an array of type ClassA to NSUserDefaults. ClassA look like this:
class ClassA :NSObject, NSCoding{
init (descriptionParam: String) {
self.description = descriptionParam
}
var description: String?
required init(coder aDecoder: NSCoder) {
if let description = aDecoder.decodeObjectForKey("description") as? String {
self.description = description
}
}
func encodeWithCoder(aCoder: NSCoder) {
if let description = self.description {
aCoder.encodeObject(description, forKey: "description")
}
}
}
This is how I'm saving the array to NSUserDefaults:
let myData = NSKeyedArchiver.archivedDataWithRootObject(ClassAManager.classa_array)
userDefaults.setObject(myData, forKey: "classAarray");
I'm doing the following in my initial viewDidLoad():
var classA: AnyObject? = NSUserDefaultsManager.userDefaults.objectForKey("classAarray") as AnyObject?
let classAunpacked = NSKeyedUnarchiver.unarchiveObjectWithData(classA) as [ClassA]
I get the following compile-time error on the second line above (the one with let):
Cannot invoke 'unarchiveObjectWithData' with an argument list of type '(AnyObject?)'
However, if I try to retrieve the array with anything other than AnyObject?, I get other compile time errors. It also seems I can't cast from AnyObject? to [ClassA]. Any ideas how this should be done?
unarchiveObjectWithData takes an NSData as it's sole argument, not an optional AnyObject. Since the result of unarchive... is also an optional, I'd suggest using:
if let classA = NSUserDefaultsManager.userDefaults.dataForKey("classAarray") {
if let classAunpacked = NSKeyedUnarchiver.unarchiveObjectWithData(classA) as? [ClassA] {
// Use classAunpacked here
}
}

Instance properties with default values in Swift: when are they called?

Say I have a class like this one:
class UniverseViewController: UITableViewController {
var model = createModel()
// blah, blah...
}
When exactly will the createModel function be called? Before the init? After it?
It is called before init and viewDidLoad etc.
The following code:
struct testStruct {
init() {
println("testStruct")
}
}
let tempValue = testStruct()
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
println("Coder")
}
override func viewDidLoad() {
super.viewDidLoad()
println("viewDidLoad")
}
will give us the following output:
testStruct
Coder
viewDidLoad

Resources