how to deal with stored properties's set and get in swift - objective-c

this is a way we deal with property in OC
- (void)setText:(NSString *)text
{
if ([text isEqualToString:#"ss"]) {
_text = #"xx";
return
}
_text = text;
}
- (NSString *)text
{
return _text;
}
this is a wrong way in swift, we can't call self.xx in set.
var text : NSString {
get {
return self.text
}
set {
if newValue.isEqualToString("ss") {
self.text = "xx"
} else {
self.text = newValue
}
}
}
My question is how to transfer the OC code to Swift code.

You're confusing stored properties with computed properties.
Only computed properties have a getter and an optional setter; stored properties don't have either. Also, the setter in a computed property isn't there to set the value of the computed property (it can't, as the property is, well, computed and does not have an independent existence); rather, it's used to set the values of other properties, whose values are used to compute the computed property when it's next accessed. See this post for an example of that.
Now, stored properties can have property observers. In your specific example, it would look like this:
var text : NSString! {
didSet {
if text.isEqualToString("ss" as NSString) {
text = "xx" as NSString
}
}
}
You can also have a willSet block. Note that in Swift 1.2 NSString and String are no longer automatically bridged so you need to cast them onto each other when necessary.

While I don't know much about using a getter and setter on a stored property, in your case you can just use a property observer didSet.
var text: String! {
didSet {
if text == "ss" {
text = "xx"
}
}
}

You can try this way!
var text: NSString = ""
var newText : NSString {
get {
return text
}
set {
if newValue.isEqualToString("ss") {
text = "xx"
} else {
text = newValue
}
}
}

Related

Using complex types in RedisTypedClient (ServiceStack Redis)

I have an example where I want to store an object into Redis.
class CyPoint
{
// Fields...
private bool _Done;
private string _Color;
private string _Position;
private long _Id;
public long Id
{
get { return _Id; }
set
{
_Id = value;
}
}
public string Position
{
get { return _Position; }
set
{
_Position = value;
}
}
public string Color
{
get { return _Color; }
set
{
_Color = value;
}
}
public bool Done
{
get { return _Done; }
set
{
_Done = value;
}
}
}
I am using this code to store the data
var redisCyPoint = redis.As<CyPoint>();
var cpt = new CyPoint
{
Id = redisCyPoint.GetNextSequence(),
Position = "new Vector3(200, 300, 0)",
Color = "new Vector3(.5f, .7f, .3f)",
};
redisCyPoint.Store(cpt);
This works as I am storing strings. But when I change position and color to Vector3 (which is: float, float, float) it only saves 0's. It seems that the Store will not work with complex types. Is this a limitation or is there a way to do this?
Struct's are serialized as a single scalar string value as returned by ToString(). You can implement custom support for Structs by implementing a constructor Vector3(string) that can populate itself from its ToString() value, or implement a static ParseJson(string) method.
Otherwise you can specify custom serializer to handle the serialization, e.g:
JsConfig<Vector3>.SerializeFn = v => "{0},{1},{2}".Fmt(v.X,v.Y,v.Z);
JsConfig<Vector3>.DeSerializeFn = s => {
var parts = s.Split(',');
return new Vector3(parts[0],parts[1],parts[2]);
};

How to create a static pointer variable to itself in Swift?

In Objective-C I often use the pattern of using a static void* as an identification tag. At times these tags are only used within that function/method, hence it's convenient to place the variable inside the function.
For example:
MyObscureObject* GetSomeObscureProperty(id obj) {
static void* const ObscurePropertyTag = &ObscurePropertyTag;
MyObscureObject* propValue = objc_getAssociatedObject(id,ObscurePropertyTag);
if(!propValue) {
propValue = ... // lazy-instantiate property
objc_setAssociatedObject(obj,ObscurePropertyTag,propValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return propValue;
}
The question is, how to write the ObscurePropertyTag private-constant-pointer-to-itself in Swift? (Preferrably 2.1 but future already-announced versions should be okay)
I've looked around and it seems that I have to put this ObscurePropertyTag as a member variable and there doesn't seem to be a way around it.
Unlike (Objective-)C, you cannot take the address of an
uninitialized variable in Swift. Therefore creating a self-referencing
pointer is a two-step process:
Swift 2:
var ptr : UnsafePointer<Void> = nil
withUnsafeMutablePointer(&ptr) { $0.memory = UnsafePointer($0) }
Swift 3:
var ptr = UnsafeRawPointer(bitPattern: 1)!
ptr = withUnsafePointer(to: &ptr) { UnsafeRawPointer($0) }
For your purpose, is it easier to use the address of a global variable with &, see for
example
Is there a way to set associated objects in Swift?.
If you want to restrict the scope of the "tag" to the function itself
then you can use a static variable inside a local struct. Example:
func obscureProperty(obj : AnyObject) -> MyObscureObject {
struct Tag {
static var ObscurePropertyTag : Int = 0
}
if let propValue = objc_getAssociatedObject(obj, &Tag.ObscurePropertyTag) as? MyObscureObject {
return propValue
}
let propValue = ... // lazy instantiate property value
objc_setAssociatedObject(obj, &Tag.ObscurePropertyTag,propValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return propValue
}
Try this:
var GetSomeObscureProperty: MyObscureObject = nil
withUnsafePointer(& GetSomeObscureProperty) {
GetSomeObscureProperty = MyObscureObject($0)
}
In short
let GetSomeObscureProperty = UnsafePointer<()>()

Appending JsonFile (UrL) in array to display on application

I am trying to add my data from my Json file into the application.I want append the Authors name from the Json file into the empty array.
I have added all of the areas that needed to be added when i run the simulation i get an empty array. I need it display the Authors first name on the simulator.
Does anyone know what i need to do to my code to make it work?
My Code :
var AuthorGlobal = [String]()
class ViewController: UIViewController, UITextFieldDelegate{
#IBOutlet weak var DisplayAuthor: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
DisplayAuthor.text="\(AuthorGlobal)"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
Alamofire.request(.GET, "http://178.62.83.50/newsletters.json")
.responseJSON { response in
// print(response.request) // original URL request
// print(response.response) // URL response
// print(response.data) // server data
// print(response.result) // result of response serialization
if let _ = response.result.value {
// print("JSON: \(JSON)")
}
let json = JSON(data: response.data!)
if let Author = json["NewsLetter"][0]["Author"].string {
AuthorGlobal.append(Author)
}
if let LastName = json["NewsLetter"][0]["LastName"].string {
print(LastName)
}
if let ArticleTitle = json["NewsLetter"][0]["ArticleTitle"].string {
//Now you got your value
print(ArticleTitle)
}
if let Author = json["NewsLetter"][1]["Author"].string {
//Now you got your value
print(Author)
}
if let LastName = json["NewsLetter"][1]["LastName"].string {
//Now you got your value
print(LastName)
}
if let ArticleTitle = json["NewsLetter"][1]["ArticleTitle"].string {
//Now you got your value
print ("Article Title: " + (ArticleTitle))
}
}
}
I just tried by putting your json in my file system and loading it locally. Below is my code on Swift 2 and it all worked fine. You might want to check the JSON data coming correctly in your service call. Also, try to compare it line by line with my code to see if you missed out something. Its too late for me to call it a day so bear with me to not pointing out the exact root cause in your code!
var AuthorGlobal = [String]()
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var DisplayAuthor: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// DisplayAuthor.text="\(AuthorGlobal)"
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated);
let filePath = NSBundle.mainBundle().pathForResource("1", ofType: "json")
var fileContents : String = ""
do {
fileContents = try String(contentsOfFile: filePath!, encoding: NSUTF8StringEncoding)
} catch (_) {
}
var json : Dictionary<String,Array<Dictionary<String,String>>> = Dictionary()
do {
json = try NSJSONSerialization.JSONObjectWithData(fileContents.dataUsingEncoding(NSUTF8StringEncoding)!, options:NSJSONReadingOptions.AllowFragments) as! Dictionary<String, Array<Dictionary<String, String>>>
} catch (_) {
}
let array = json["NewsLetter"] as Array?
if let author = array?[0]["Author"] {
AuthorGlobal.append(author)
}
print(AuthorGlobal) // This prints - ["Tom"]
if let LastName = array?[0]["LastName"] {
print(LastName) // This prints - Holton
}
if let ArticleTitle = array?[0]["ArticleTitle"] {
//Now you got your value
print(ArticleTitle) // This prints - XcodeGhost: Apple suffers a major malware infection inside the iOS app store.
}
if let Author = array?[1]["Author"] {
//Now you got your value
print(Author) // This prints - Sam
}
if let LastName = array?[1]["LastName"] {
//Now you got your value
print(LastName) // This prints - Devaney
}
if let ArticleTitle = array?[1]["ArticleTitle"] {
//Now you got your value
print ("Article Title: " + (ArticleTitle)) // This prints - Article Title: Google is 2 Billion Lines of Code
}
}
}

How to get the value of an annotated variable?

So, I'm writing a method that will get annotated variables (doubles) and store them in a map. The variables are elements of an object. The name of the variable should be the key and its value - the parameter.
public void putInMap() {
Field[] fields = this.getClass().getDeclaredFields();
for (Field v: fields) {
if (v.isAnnotationPresent(Annotation.class))
map.put(v.getName(), *value here* );
}
}
My question is how to get the value of the variable (which is now a Field) so that I could put it in my map?
Try:
for (Field v : fields) {
if (v.isAnnotationPresent(Annotation.class)) {
v.setAccessible(true);
map.put(v.getName(), v.get(this));
}
}

QML ListModel and custom function property

I want to write tuned version of TableView (TableView.qml in Qt package).
I have ColumnDescriptor.qml with column definition:
Item {
property string title
property var formatDelegate: null
.... (other property definition)
function format(val) {
if (formatDelegate != null)
return formatDelegate(val);
else
return val;
}
}
The above code defines set of properties and fuction format(val), that calls for format value if formatDelefate was set.
In the main table I use list to store predefined columns definition (temporaly) and ListModel to store final columns definition ( the latter is more useful than list in remaining implementation)
list example:
property list<ColumnDescriptor> colDefines: [
ColumnDescriptor {
title: qsTr("col1")
},
ColumnDescriptor {
title: qsTr("col2")
formatDelegate: function(val) { return "!" + val}
}
]
Filling ListModel (id: columnModel):
Component.onCompleted: {
for(var i = 0; i < colDefines.length; ++i)
{
var col = colDefines[i];
...(some calculation)
columnModel.append(col);
}
}
All looks fine, but when I try to call format from model item, Qt sends me the following error
Property 'format' of object QQmlDMListAccessorData(0x8e3bf78) is not a function
Example of calling format:
Repeater {
model: columnModel
Text {
text: model.format([SOME USEFUL DATA])
}
}
On the other hand, if I call format directly from list it works well.
So my question here is how to fill model in a way that the format or other function will work correctly when being called from model?
For QtQuick2 this should work
formatDelegate = [function(val) { return "!" + val}]
formatDelegate[0]("some text")
but you could also use an overriding technique:
Item {
function formatDelegate(val) {
return val;
}
function format(val) {
return formatDelegate(val);
}
}
ColumnDescriptor {
function formatDelegate(val) {
return "!" + val
}
}
This way Item.format() should call "return val" as default and "!"+val for ColumnDescriptor given that ColumnDescriptor is derived from Item.
Try this
Repeater {
model: columnModel
Text {
text: columnModel[index].format([SOME USEFUL DATA])
}
}