Ios Grouped Barchart, do not paint zero or empty values - ios

I don't want to dislay the zeros on my group bar chart
I am using ios charts library, is there any way I can get rid of the zeros?
You can check the image here:
https://drive.google.com/file/d/0B0_KV3MPKH8RYWRQV0lhbU43VVk/view?usp=sharing

Based on your requirement here you can use Formatter Delegate IChartValueFormatter and return nil value to that delegate method.
Check this code :
1st-Confirm Protocol for value formatter :
#interface ViewController ()<IChartValueFormatter>
2nd-Assign Delegate to Value Formatter :
BarChartDataSet *set1 = [[BarChartDataSet alloc] initWithValues:arrVals1];
set1.valueFormatter = self;
3rd-Implement Value Formatter method:
#pragma mark - IChartValueFormatter
- (NSString * _Nonnull)stringForValue:(double)value entry:(ChartDataEntry * _Nonnull)entry dataSetIndex:(NSInteger)dataSetIndex viewPortHandler:(ChartViewPortHandler * _Nullable)viewPortHandler{
if (value>0) {
return [NSString stringWithFormat:#"%0.f",value];
}else{
return nil;
}
}
return nil while value is less than 0.
Hope this will helps.

Related

Intersecting two NSArrays with non-comparable objects inside

The following code receives an array of events from EventKit for the selected day, then "pads" the existing calendar events with empty events to fill hourly slots from the entire day (9-5, for example).
The events coming from the iOS calendar are contained within a custom event container class that I created. The event class has the following properties:
// HDEvent.h
#interface HDEvent : NSObject
#property(nonatomic, copy) NSDate *startDate;
#property(nonatomic, copy) NSDate *endDate;
#property(nonatomic, strong) EKEvent *event;
#property(nonatomic, copy) NSString *eventIdentifier;
#property(nonatomic, copy) NSString *tempTitle;
#end
I am attempting to replace the empty events with any true events from the calendar, based on the start/end dates of the HDEvent object. The incoming array for the following method has the events (if any) from the device calendar.
- (NSArray *)addEmptyEventsWithEvents:(NSMutableArray *)events
ForDate:(NSDate *)date {
NSMutableOrderedSet *finalEvents = [[NSMutableOrderedSet alloc] init];
// this returns an array filled with the empty HDEvents
// for the expected date range.
NSArray *emptyEvents = [self getEventsTimeRangeFromDate:date];
for (HDEvent *emptyEvent in emptyEvents) {
HDEvent *eventToAdd;
for (HDEvent *event in events) {
NSLog(#"Event: %#", event.event.title);
if ([event.startDate isEqualToDate:emptyEvent.startDate] ||
[event.endDate isEqualToDate:emptyEvent.endDate])
{
eventToAdd = event;
} else {
eventToAdd = emptyEvent;
}
}
[finalEvents addObject:eventToAdd];
}
return [finalEvents array];
}
I am attempting to create an array with my events as illustrated in the pseudo-code below:
// Calendar Events
[
10:00-11:00 MEETING,
11:00-12:00 LUNCH
]
// Empty Placeholders
[
09:00-10:00 EMPTY,
10:00-11:00 EMPTY,
11:00-12:00 EMPTY,
12:00-01:00 EMPTY,
01:00-02:00 EMPTY,
02:00-03:00 EMPTY,
03:00-04:00 EMPTY,
04:00-05:00 EMPTY,
]
// Final desired result:
[
09:00-10:00 EMPTY,
10:00-11:00 MEETING,
11:00-12:00 LUNCH,
12:00-01:00 EMPTY,
01:00-02:00 EMPTY,
02:00-03:00 EMPTY,
03:00-04:00 EMPTY,
04:00-05:00 EMPTY,
]
[Problem]:
The problem is that the array returned only contains one event from the calendar (though I can see in the NSLog response that I have two events on that day)
If I swap the for loops around, then I get 9 events (again, only one from the calendar, and one duplicate empty event.)
Thank you #vikingosegundo.
I ended up implementing a custom comparison method in my class following the advice contained in this answer here: https://stackoverflow.com/a/877881/810360
I also extended it to be more flexible by utilizing the excellent DateTools by Matthew York found on GitHub: https://github.com/MatthewYork/DateTools
This was my final code:
-(BOOL)isEqualToEvent:(HDEvent*)event {
if (self == event) {
return YES;
}
if ([event.startDate isEqualToDate:self.startDate] &&
[event.endDate isEqualToDate:self.endDate]) {
return YES;
} else {
return NO;
}
}
-(BOOL)doesEventIntersectEvent:(HDEvent*)event {
DTTimePeriod *eventTimePeriod = [DTTimePeriod timePeriodWithStartDate:event.startDate endDate:event.endDate];
DTTimePeriod *selfTimePeriod = [DTTimePeriod timePeriodWithStartDate:self.startDate endDate:self.endDate];
if ([eventTimePeriod intersects:selfTimePeriod]) {
return YES;
} else {
return NO;
}
}
-(BOOL)doesEventContainEvent:(HDEvent*)event {
DTTimePeriod *eventTimePeriod = [DTTimePeriod timePeriodWithStartDate:event.startDate endDate:event.endDate];
DTTimePeriod *selfTimePeriod = [DTTimePeriod timePeriodWithStartDate:self.startDate endDate:self.endDate];
if ([eventTimePeriod contains:selfTimePeriod]) {
return YES;
} else {
return NO;
}
}

How to call function at other class in objective-c?

I am developing in Objective-C.
I create the two file call AAA.m and BBB.m.
1. In the AAA.m , I call a function readValue in BBB.m and send a NSString.
2. In the BBB.m , I receive the NSString from AAA.m , and then call the function updateState in AAA.m.
3. When the updateState in AAA.m has been called from BBB.m. It set the value from BBB.m to the UISlider.
The code is like the following:
AAA.m
#property (strong,nonatomic)BBB *bbb;
- (void)viewDidLoad
{
[self.bbb initAAA];
[self.WhiteSlider setMinimumValue:0];
[self.WhiteSlider setMaximumValue:100];
}
- (IBAction)SyncLEDState:(id)sender {
[self.bbb readValue:#"50"];
}
- (void)updateState:(NSString*)state
{
NSlog(#"state = %#",state);
self.WhiteSlider.value = [state intValue];;
}
BBB.m
#property (strong,nonatomic)AAA *aaa;
-(void)initAAA
{
self.aaa = [[AAA alloc] init];
}
-(void)readValue:(NSString*)string
{
NSlog(#"string = %#",string);
[self.aaa updateState:string];
}
I already receive the value in updateState function which called by BBB.m.
But I can not update the value of UILabel or UISlider in AAA.m.
I am sure the UISlider did not has problem.
Is BBB.m create a new AAA.m due to self.aaa = [[AAA alloc] init]; , so it did not change the value of UISlider at original AAA.m?
Did I missing something ? Thanks in advance.
BBBcreates its own private version of AAAin self.aaa that is different from the aaa in the call to its readValue:. Hence you are (presumably) updating the state of an AAA that is not displayed.
Alternatively, you could modify your current version approx. as follows:
in AAA.m:
self.bbb = [[BBB alloc] initWithAAA: self];
in BBB.m:
- (id)initWithAAA: (AAA *)aaa {
self = [super init];
if (self)
self.aaa = aaa;
return self;
}
This would make sure that both AAA and BBB refer to the same instance of AAA.

Putting a character range in UITextFields

How come this code isn't working to set a character limit in XCode?
I wrote it in my viewDidLoad() under ViewController.m
NSNumberFormatter* formatter= [[NSNumberFormatter alloc]init];
NSFormatter.numberStyle= NSNumberFormatterDecimalStyle;
formatter.allowsFloats= NO;
formatter.minimum= #5;
formatter.maximum= #15;
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [formatter numberFromString: textField.text]!= nil;
}
Errors:
http://imgur.com/h83hzsw
From the errors, it looks like you're not using this code inside an actual method (such as viewDidLoad) Since you need it in multiple methods, you'll need your formatter to be accessible throughout the class. Try moving things around a bit:
#implementation ViewController
{
NSNumberFormatter *formatter;
}
...
- (void)viewDidLoad
{
...
formatter = [[NSNumberFormatter alloc] init];
formatter.numberStyle= NSNumberFormatterDecimalStyle;
formatter.allowsFloats= NO;
formatter.minimum= #5;
formatter.maximum= #15;
}
You are getting the error 'Initializer element is not a compile-time constant' because you are initialising the variable NSNumberFormatter* formatter not in a method or function and the compiler therefor expects a constant value.
See SO answer here for more detail - Initializer element is not a compile-time constant

Is there anyway I can compare a String (which is a word) and a letter which is input by the user and receive an output as a BOOL

I'm new to IOS dev and am making simple programs this one is a hangman game.
I wanted to pick a random string from a plist file (completed).
I now want to compare the user input text (from a text field) and compare it to the string we have randomly picked from our plist.
Here is my code for MainViewController.m as it is a utility. Only the MainView is being used currently.
#import "MainViewController.h"
#import "WordListLoad.h"
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize textField=_textField;
#synthesize button=_button;
#synthesize correct=_correct;
#synthesize UsedLetters=_UsedLetters;
#synthesize newgame=_newgame;
- (IBAction)newg:(id)sender
{
[self start];
}
- (void)start
{
NSMutableArray *swords = [[NSMutableArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"swords" ofType:#"plist"]];
NSLog(#"%#", swords);
NSInteger randomIndex = arc4random() % [swords count];
NSString *randomString = [swords objectAtIndex:randomIndex];
NSLog(#"%#", randomString);
}
This is where i would like to implement the checking
I have tried characterAtIndex and I can't seem to get it to work for hard coded placed in the string let along using a for statement to systematic check the string.
- (void)check: (NSString *) randomString;
{
//NSLogs to check if the values are being sent
NSLog(#"2 %#", self.textField.text);
}
- (IBAction)go:(id)sender
{
[self.textField resignFirstResponder];
NSLog(#"1 %#", self.textField.text);
[self check:(NSString *) self.textField];
_textField.text = nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self start];
}
To compare 2 strings: [string1 equalsToString:string2]. This will return true if string1 is equal to string2. To get the string contained in a UITextfield: textfield.text.
Given that it's a hangman game, I assume you are trying to see if a single letter is contained by a given string - so equalsToString: wouldn't be what you want.
Instead, probably better to use rangeOfString:options:
if ([randomString rangeOfString:self.textfield.text options:NSCaseInsensitiveSearch].location != NSNotFound){
// Do stuff for when the letter was found
}
else {
// Do stuff for when the letter wasn't found
}
Also, as was pointed out by Patrick Goley, you need to make sure you're using the textfield.text value to get the string from it. Same with storing the initial word you'll be using as the hidden word.
There are also a couple of other minor code issues (semicolon in the function header, for example) that you'll need to clean up to have a functioning app.
Edit: Made the range of string call actually use the textfield's text, and do so case-insensitive (to prevent false returns when a user puts a capital letter when the word is lower case, or vice-versa). Also included link to documentation of NSString's rangeOfString:options:
For your check method you are sending the UITextfield itself, instead of its text string. Instead try:
[self check: self.textfield.text];
You'll also need to create an NSString property to save your random string from the plist, so you can later access to compare to the textfield string like so:
declare in the interface of the class:
#property (nonatomic,strong) NSString* randomString;
in the start method:
self.randomString = [swords objectAtIndex:randomIndex];
in the check method:
return [self.randomString isEqualToString:randomString];

Overriding "text" in UILabel does not work in iOS 6

My class "TypographicNumberLabel" is a subclass of UILabel. This class overrides the "text" setters and getters of UILabel with the purpose to produce nicely rendered numbers in a table. For instance, it can add some extra white space for right alignment, unary plus signs, append units, etc.
My problem is that this class has worked perfectly fine up to iOS 5.1, but in iOS 6, it has stopped working: It is now rendering exactly as the standard UILabel (but when its properties are accessed from code, they are still giving correct results).
Since this class is used in a huge mass of legacy code, I would really like to repair my original code instead of rewriting it using completely new methods. So, please focus your answers on explaining how to override "-text" and "-setText:" for UILabel in iOS 6.
This is (a simplified version of) my code:
#interface TypographicNumberLabel : UILabel {
NSString *numberText;
}
// PROPERTIES
// "text" will be used to set and retrieve the number string in its original version.
// integerValue, doubleValue, etc. will work as expected on the string.
// The property "text" is declared in UILabel, but overridden here!
// "typographicText" will be used to retrieve the string exactly as it is rendered in the view.
// integerValue, doubleValue, etc. WILL NOT WORK on this string.
#property (nonatomic, readonly) NSString* typographicText;
#end
#implementation TypographicNumberLabel
- (void) renderTypographicText
{
NSString *renderedString = nil;
if (numberText)
{
// Simplified example!
// (Actual code is much longer.)
NSString *fillCharacter = #"\u2007"; // = "Figure space" character
renderedString = [fillCharacter stringByAppendingString: numberText];
}
// Save the typographic version of the string in the "text" property of the superclass (UILabel)
// (Can be retreived by the user through the "typographicText" property.)
super.text = renderedString;
}
#pragma mark - Overridden UILabel accessor methods
- (NSString *) text
{
return numberText;
}
- (void) setText:(NSString *) newText
{
if (numberText != newText)
{
NSString *oldText = numberText;
numberText = [newText copy];
[oldText release];
}
[self renderTypographicText];
}
#pragma mark - TypographicNumberLabel accessor methods
- (NSString *) typographicText
{
return super.text;
}
#end
Example of use (aLabel is loaded from .xib file):
#property(nonatomic, retain) IBOutlet TypographicNumberLabel *aLabel;
self.aLabel.text = #"12";
int interpretedNumber = [self.aLabel.text intValue];
This type of code works perfectly fine in both iOS 5.1 and in iOS 6, but the rendering on screen is wrong in iOS 6! There, TypographicNumberLabel works just like a UILabel. The "figure space" character will not be added.
The issue is at
- (NSString *) text
{
return numberText;
}
You can see the method ([self text]) is called internally, so it's better to return the text you want to be shown, otherwise you can easily ruin internal control logic:
- (NSString *) text
{
return [super text];
}
After having submitted my question, I found a solution myself. Perhaps not the definite solution, but at least a useful workaround. Apparently, the rendering logic of UILabel has changed when attributedText was introduced in iOS 6. I found that setting the attributedText property instead of super.text will work.
To be more specific:
The following line in renderTypographicText
super.text = renderedString;
should be replaced with
if (renderedString && [UILabel instancesRespondToSelector: #selector(setAttributedText:)])
super.attributedText = [[[NSAttributedString alloc] initWithString: renderedString] autorelease];
else
super.text = renderedString;
then the rendering works fine again!
This is a bit "hackish", I admit, but it saved me from rewriting a huge amount of legacy code.

Resources