class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var _email: MaterialField!
#IBOutlet weak var _pass: MaterialField!
#IBOutlet weak var _signIn: UIButton!
#IBAction func attemptLoginWithEmail(sender : UIButton!) {
if let email = _email.text where email != "", let password = _pass.text where password != "" {
print(email)
}
}
Program keeps crashing , the _email.text and _pass.text keep returning nil. tried for a few hours but couldn't get it to work. any help would be appreciated
Just simply remove weak keyword from at the time of object preparation and now run your project its worked well.
Note :
A strong reference (which you will use in most cases) means that you want to "own" the object you are referencing with this property/variable. The compiler will take care that any object that you assign to this property will not be destroyed as long as you point to it with a strong reference. Only once you set the property to nil will the object get destroyed (unless one or more other objects also hold a strong reference to it).
In contrast, with a weak reference you signify that you don't want to have control over the object's lifetime. The object you are referencing weakly only lives on because at least one other object holds a strong reference to it. Once that is no longer the case, the object gets destroyed and your weak property will automatically get set to nil. The most frequent use cases of weak references in iOS are:
1.) delegate properties, which are often referenced weakly to avoid retain cycles, and
2.) subviews/controls of a view controller's main view because those views are already strongly held by the main view.
I am not sure what it was but I deleted func attemptLogin and made another function exactly the same referring the same button and it worked. thanks for those of you who commented
Related
I am not understanding how to give weak refrence to the array or release allocated memory of array, can anyone tell me how to fix this leak?
var menuDetails:[[String:Any]] = []//this my global array object
Getting following leak even i am using ARC.
Screenshot for array memory leak!
I was just scared about that memory leak,can anyone tell how do i fix it?
You don't want to use a weak reference. If you do that your array will get released immediately.
weak var weakArray: [[String:Any]]? = []
Will contain nil as soon as you create it.
Instead, you should set the array to nil (or empty) once you're done with the contents:
You could use `menuDetails.removeAll() to delete all the entries in the array, or you could change your declaration to make it an Optional
var menuDetails:[[String:Any]]? = []//this my global array object
And then set it to nil when you're done with it:
menuDetails = nil
An object will only be retained if another object has a strong reference to it. As soon as your view controller disappears, it will most likely be deallocated as well, which automatically removes its strong references to other objects. Thus, if imageArray is strongly referenced only by your disappearing view controller, the memory will automatically be released. You do not need to use an autoreleasepool.
In order to store weak references in arrays and/or dictionaries, you need an intermediate structure.
for example:
struct WeakRef
{
weak var object:AnyObject?
init( _ objectRef:AnyObject?)
{ object = objectRef }
}
// use WeakRef when you add object instances to your dictionary (or array)
menuDetails[0]["objectKey"] = WeakRef(yourObject)
// you will need additional code to get the actual object out of the intermediate structure
// and given that it is a weak reference you'll also need to deal with its optionality.
if let yourObject = (menuDetails[0]["objectKey"] as? WeakRef)?.object as? YourClass,
{
// ... do your thing with your object ...
}
The syntax could probably be made more legible by wrapping this in custom operators and generics but this is the general approach to it.
today I faced a problem , the vc never call deinit, so I added a weak
func showAddCityViewController() {
weak var vc:SWAddCityViewController!
vc = SWAddCityViewController()
vc.delegate = self
let nav = UINavigationController(rootViewController: vc)
dispatch_async(dispatch_get_main_queue(), {
self.presentVC(nav)
})
}
I run this function and then get a
fatal error: unexpectedly found nil while unwrapping an Optional value
the vc just go to nil ,but I don't know why , what should I do to make this code happy?
You wrote this:
weak var vc:SWAddCityViewController!
vc = SWAddCityViewController()
The vc variable is an “implicitly unwrapped Optional”, which means it can either point to an existing (not-deallocated) object, or it can be nil.
You create a new SWAddCityViewController object and assign it to vc. After the assignment statement completes, there is exactly one weak reference to the new object (in vc) and there are no strong references to it. An object is deallocated as soon as it has no strong references, so it is deallocated as soon as the assignment statement completes.
Since vc was a weak reference to the object, part of deallocating the object sets vc to nil. When you try to set vc.delegate on the next line, Swift generates code to unwrap vc automatically (since you declared it with !). Since vc is nil, you get a fatal error. You cannot unwrap an optional that's set to nil because it's not wrapping anything.
I don't see any reason to declare vc weak in that function. Just get rid of the weak attribute.
Your other complaint is that (with weak) the object doesn't get deallocated later. You have a “retain cycle”. Did you declare the delegate property of SWAddCityViewController using weak? You usually want to declare delegate properties weak.
If that doesn't fix the problem, you need to look for other places where you have a retain cycle involving the object.
First q here, so trying to get protocol right...what I've done works, in that the data and views display correctly, but memory is not deallocating (still getting used to ARC after many years of allocating/deallocating), and I'm trying to figure out the right strategy. Document based app. When doc is created, view controller is instantiated, which creates several views which need to refer to each other for size/position/methods, and all of which need access to the doc data.
class MyDoc: UIDocument {
var data: Int
etc...
}
class MyController: UIViewController {
var doc: myDoc! // code which creates MyDoc instance assigns self to this property
var thisView1: MyView1!
var thisView2: MyView2!
thisView1 = MyView1(...)
thisView2 = MyView2(...)
thisView1.theOtherView2 = thisView2
thisView2.theOtherView1 = thisView1
thisView1.doc = self.doc
thisView2.doc = self.doc
}
class MyView1: UIView {
var theOtherView2: MyView2!
var doc: MyDoc!
}
class MyView2: UIView {
var theOtherView1: MyView1!
var doc: MyDoc!
}
I don't think I excluded anything meaningful. Assigning thisView1 and thisView2 to each other creates a strong reference cycle, right? I tried combining an unowned property on one with implicitly unwrapped on the other, per The Swift Programming Language, but kept having trouble with the init() methods of the views. Is using weak references and then unwrapping the optional all the time (though I make sure there's a valid value before proceeding from viewController) the only thing that'll work? I've read so many explanations that each new one now confuses me more.
Thank you!
All I'm trying to do is get the text input from a UITextField object on my main.storyboard. Both #IBOutlet objects show that they are linked to the correct text field objects. However, when I try to make the constant meenieOneText take on the value of the .text property of the meenieOne UITextField, I get the error message "Instance member 'meenieOne' cannot be used on type 'ViewController'.
I'm really new at this so I could be doing something simple completely wrong, but I'm at my wit's end with this because it looks right to me.
Any help is much appreciated.
Thanks in advance!
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var meenieOne: UITextField!
#IBOutlet weak var meenieTwo: UITextField!
let meenieOneText: String = meenieOne.text
Try this instead:
var meenieOneText: String = ""
override func viewDidLoad() {
super.viewDidLoad()
meenieOneText = meenieOne.text!
}
You have a problem, because in iOS the Storyboard elements, while accessible, may not have been initialised (eg. the user cannot see them) as you try to access their properties. The easiest way to ensure the elements are initialised, you would access them after viewDidLoad(). There are also other phases such as 'viewDidDisappear' and so forth. See Apple documentation on ViewControllers here:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/
You can not use properties of UITextField directly in class. Write same code in any function. Its work properly.
I came across a strange behaviour in Swift while programming a Master-Detail application.
Here's the scenario:
It's a simple Task Manager application. I have two text controls (TaskName, TaskDescription) on the TaskDetailView and two string variables with the same name but in lowerCamelCase (taskName, taskDescription) declared in the TaskDetailViewController.
#IBOutlet var TaskName:UITextField! //UpperCamelCase
#IBOutlet var TaskDescription:UITextView! //UpperCamelCase
var taskName:String? //lowerCamelCase
var taskDescription:String? //lowerCamelCase
I am setting the values of Text controls on ViewDidLoad() as usual:
override func viewDidLoad() {
super.viewDidLoad()
TaskName.text = taskName
TaskDescription.text = taskDescription
}
And I am passing the data in prepareForSegue (from TaskListViewController) as usual:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if(segue.identifier == "TaskListSegue"){
let detailViewController = segue.destinationViewController as ToDoTaskViewController
let (task, desc) = m_ToDoListManager.GetTask(TaskListView.indexPathForSelectedRow().row)
println("selected \(task) \(desc)")
detailViewController.taskName = task
detailViewController.taskDescription = desc
}
}
The way everything is implemented is correct.
But now when you run the application, the values of text controls are not set.
In fact, the values of the variables also are not set.
What must be happening here?
I have already investigated this problem and also came up with a solution (see my answer below). Please also see Martin R's answer below for a detailed explanation. I just wanted to share this with everyone. I am not sure if anyone has come across this issue.
Update:
Here's the actual code:https://github.com/Abbyjeet/Swift-ToDoList
Here is an explanation:
Your Swift class is (ultimately) a subclass of NSObject.
Therefore the properties are Objective-C properties with getter and setter method.
The name of the setter method for a property is built by capitalizing the first
letter of the property name, e.g. property "foo" has the setter method setFoo:
As a consequence, the setter method for both properties TaskName and taskName is called setTaskName:.
In an Objective-C file, you would get a compiler error
synthesized properties 'taskName' and 'TaskName' both claim setter 'setTaskName:' - use of this setter will cause unexpected behavior
but the Swift compiler does not notice the conflict.
A small demo of the problem:
class MyClass : NSObject {
var prop : String?
var Prop : String?
}
let mc = MyClass()
mc.prop = "foo"
mc.Prop = "bar"
println(mc.prop) // bar
println(mc.Prop) // nil
In your case
TaskName.text = ...
sets the "taskName" property, not the "TaskName". The properties have different type,
so that the behavior is undefined.
Note that the problem does only occur for "Objective-C compatible" properties. If you remove the
NSObject superclass in above example, the output is as expected.
Conclusion: You cannot have two Objective-C properties that differ only in the
case of the first letter. The Swift compiler should fail with an error here (as the
Objective-C compiler does).
The problem you were facing with was not connected to the swift language. Method prepareForSegue is called before loadView. That mean UITextField and UITextView are not initialized yet. That's why fields were not initialized.
You also asked: Why compiler doesn't show any error? That's because any selector performed on nil object doesn't throw an exception. So for example (sorry for obj-c):
UITextField *tf = nil;
[tf setText:#"NewText"];
Will not show any error.
As you said on your own answer to solve your problem you need to add additional fields to your destination controller (copy-paste):
var tAskName:String? //cUstomCamelCase
var tAskDescription:String? //cUstomCamelCase
Why is it happening?
I believe that internally Swift is using lowerCamelCase for text controls names which are not yet initialized and thus failing to set the values. But it is also strange that I didn't get any kind of error.
How did I solve it?
I know that the Swift is case-sensitive. So that was not the issue. So I just changed the case of one letter and named the variables as (tAskName, tAskDescription) and the values were set as expected.
#IBOutlet var TaskName:UITextField! //UpperCamelCase
#IBOutlet var TaskDescription:UITextView! //UpperCamelCase
var tAskName:String? //cUstomCamelCase
var tAskDescription:String? //cUstomCamelCase
So the conclusion is that if I have a control named TaskName, I cannot have a variable named as taskName