How to Resolve This Build Issue - Cannot Assign to Property: 'Date' Is a Get Only Property

How do I resolve this build issue - cannot assign to property: 'date' is a get only property

Your date is actually a computed property that only has a getter
So it can only be read, not written too.

In contrast your FullDate is a stored property.

computed properties are often used to hide functionality from other classes or expose buried data in a convenient way.

Below there is some illustration in the SomeClass object.

  • stored properties are just regular old properties
  • computed properties are getters and maybe also setters. A good example is height and width of CGRect, these are actually from CGRect.size but are implemented as convenience getters
  • property observers are functions executed when stored properties change value. didSet and willSet
  • access control on get and set allows you to create stored properties that are read or write only depending on access.

class SomeClass {

// just a variable
var storedProperty : Int = 10

// just a variable but the setter is hidden from other "files"
private(set) var storedPropertyWithPartialAccessControl : Int = 0

// only calculates when set
var derivedProperty : Int = 0 {
didSet {
storedProperty = doStuffs(derivedProperty)
}
}

// calculates every get and set
var computedProperty : Int {
get { // get is needed
return doStuffs(storedProperty)
}
set(value) { // set is not needed, using only get gives you a read only property
storedProperty = doReverseStuffs(value)
}
}

// hidden functions that are used in the computed property
private func doStuffs(value:Int) -> Int {
return value * 10
}

private func doReverseStuffs(value:Int) -> Int {
return value / 10
}
}

Because NSDateFormatter is very inefficient, it is very bad to use it in a computed property. One will be created every get. A lot of time and energy will be wasted because the resulting value might be the same most of the time.

Best practice :

  • Use computed properties to get stored properties and set to do calculations.
  • Use a Singleton to store the NSDateFormatter

A much much better way to go:

class SomeEvent {

// Store calculated results.
// This is private to make the class cleaner in use.
private var storedDate : NSDate?

private var storedFormattedDate : String = ""

// get returns stored values without calculations
// set updates both stored values after calculations
var date : NSDate? {
get {
return storedDate
}
set(value) {
storedFormattedDate = format(date: value)
storedDate = value
}
}

var formattedDate : String {
get {
return storedFormattedDate
}
set(value) {
storedDate = readDateFrom(dateString: value)
storedFormattedDate = format(date: storedDate)
}
}

// hidden functions, again to make the class cleaner in use.
private func format(date maybeDate:NSDate?) -> String {

guard let date = maybeDate else {
return ""
}
guard let dateFormatter = MyDateFormatter.shared().dateFormatter else {
return ""
}
return dateFormatter.stringFromDate(date)

}

private func readDateFrom(dateString string:String) -> NSDate? {

// get detector
if let detector = MyDateFormatter.shared().dateReader {
// results
let matches = detector.matchesInString(string, options: [], range: NSRange(location: 0, length: string.characters.count))
// first result
if let match = matches.first, let date = match.date {
return date
}
}

// just format if there is no detector
if let dateFormatter = MyDateFormatter.shared().dateFormatter {
if let date = dateFormatter.dateFromString(string) {
return date
}
}

// everything failed
return nil
}
}

Singleton to store the NSDateFormatter and NSDataDetector:

Google: Swift Singleton

class MyDateFormatter {

private static var privateShared : MyDateFormatter?

var dateFormatter : NSDateFormatter?
var dateReader : NSDataDetector?

class func shared() -> MyDateFormatter {
guard let uwShared = privateShared else {
privateShared = MyDateFormatter()
return privateShared!
}
return uwShared
}

class func destroy() {
privateShared = nil
}

private init() {
dateReader = try? NSDataDetector(types: NSTextCheckingType.Date.rawValue)
dateFormatter = NSDateFormatter()
dateFormatter!.dateFormat = "EEEE MMM dd"
}
}

Tests:

let event = SomeEvent()
event.formattedDate = "tomorrow"
event.formattedDate // "Friday Dec 04"
event.formattedDate = "25/02/2010"
event.formattedDate // "Thursday Feb 25"
event.formattedDate = "Sunday Mar 13"
event.formattedDate // "Sunday Mar 13"

Cannot assign to property: 'xxxx' is a get-only property

The error occurs because you did not tell the compiler what to do if the value of currentBook is mutated. The compiler assumes it is immutable.

Just add a setter so that the compiler knows what to do when you set the value:

var currentBook: Book {
get { return books[books.count - 1] }
set { books[books.count - 1] = newValue }
}

Or, consider using books.last!:

books.last!.position = CGPoint.zero

Cannot assign to property: 'selectedDealClosingDate' is a get-only property - SwiftUI

Think about what happens when the user changes the selection using the date picker - you would want selectedDealClosingDate to be set to the newly selected value, don't you? But look at the way you have declared selectedDealClosingDate! You've only defined how to compute its value, but not how to set its value.

var selectedDealClosingDate: Date {
var dealClosingDate = deal.dealClosingDate
dateFormatter.dateFormat = "dd/MM/YY"

return dateFormatter.date(from: dealClosingDate) ?? Date.now
}

You should add a setter:

var dateFormatter = {
let formatter = DateFormatter()
formatter = .dateFormat = "dd/MM/yy"
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
var selectedDealClosingDate: Date {
get {
var dealClosingDate = deal.dealClosingDate
return dateFormatter.date(from: dealClosingDate) ?? Date.now
}
set {
deal.dealClosingDate = dateFormatter.string(from: newValue)
}
}

Also, I find it a bit weird that you are storing a deal closing date in Core Data as a string. You might want to reconsider that.

Cannot assign to property: 'outputs' is a get-only property

The issue is that ViewModelOutputsType can either be a value or reference type. If it is a value type, then mutating any of its properties mutates the instance itself. You can resolve the issue by making the protocol class constrained and hence guaranteeing it to be a reference type.

protocol ViewModelOutputsType: class {
var didReceiveServiceError: ((Error) -> Void) { get set }
var reloadData: (() -> Void) { get set }
}

Cannot assign to property: 'b0' is a get-only property

Here's my first attempt at a fix. The extension currently only has a getter, so we'll edit that extension to replace the lines to something like this:

var b0 : Bool {
get {return ((self & 0x1) == 0) ? false : true}
set {self = newValue ? self & 0x1 : self ^ 0x1}
}

var b1 : Bool {
get {return ((self & 0x2) == 0) ? false : true}
set {self = newValue ? self | 0x2 : self ^ 0x2}
}

Hopefully I got the bitset stuff right (it's not my strong suit).

how to assign value to a get-only property

You have two problems.

First, as you have discovered, you can't modify vote because it is a computed property. Its value is determined by the code in its getter method. Assigning a value doesn't make sense.

I guess you have used a computed property because your JSON source is, frankly, awful. Integers should be sent as integers, not strings.

Assuming you can't change the JSON to something more sensible, then you will just need to update the underlying DOUBAN_VOTES property in your upVote function. You will need to make DOUBAN_VOTES a var, not a let.

This will reveal your second problem; Structs are immutable. In order to allow a function to change a value, it must be flagged as a mutating function.


var DOUBAN_VOTES:String

mutating func upVote(newVote: Int) {
self.DOUBAN_VOTES = "\(newVote)"
}

Swift error saying it cannot assign to property due to it being a 'let' constant

You are accessing the local variable captureDevice, not the struct's captureDevice variable.

Just replace the line causing the error to the following:

self.captureDevice?.exposureMode = .continuousAutoExposure

Note the self. before captureDevice.

You might think of changing the conditional binding to using var instead of let, but that won't actually work. This is because you are just mutating a local copy. It will fix the compile error but the logic won't work.

Cannot assign to property: 'desc' is a 'let' constant


    class infoViewController: UIViewController {

var result:Data1!

override func viewDidLoad() {
saveToJsonFile(result2 : &result!)
}

func saveToJsonFile(result2 : inout Data1) {
result2.data[1].monday[1].desc = "cos"
}
}

struct Data1{
var data: [Monday]
}
struct Monday {
var monday: [Desc]
}
struct Desc{
let desc: String
}

If you try as above you will get "Cannot assign to property: 'desc' is a 'let' constant" error.
So you need to change the let into var, because let is immutable.

class infoViewController: UIViewController {

var result:Data1!

override func viewDidLoad() {
saveToJsonFile(result2 : &result!)
}

func saveToJsonFile(result2 : inout Data1) {
result2.data[1].monday[1].desc = "cos"
}
}


struct Data1{
var data: [Monday]
}
struct Monday {
var monday: [Desc]

}
struct Desc{
var desc: String
}


Related Topics



Leave a reply



Submit