I am using UIActionsheet uipickerview in my project. Here, I am passing value according to his id.
I mean, in uipickerview list it will show name, and after passing it takes its id.
So, for 5-10 values it is ok, but suppose I have more than 100 values with its id, then it takes to much time to scroll, find and select a value.
So, I want to add search option in it. So after clicking my Text Field that picker or pop up will come. And it shows some list first, as well as search option available there so user can type any one or two words, so according its words data will come according to word (auto search complete).
How can I implement it.
If Anyone wants it in swift...
Create a textField with name txtSearch and then in ViewDidload add below two lines
self.txtSearch.delegate=self
self.txtSearch.addTarget(self, action: #selector(self.textFieldValueChanged(TextField:)), for: UIControlEvents.editingChanged)
func textFieldValueChanged(TextField:UITextField)
{
if((TextField.text?.characters.count)!>0)
{
self.filteredArray = (self.searchInArray(srchArray: self.ArraywithFullData, withKey: "key value", Characters: TextField.text!))!
}
else
{
self.filteredArray = self.ArraywithFullData.mutableCopy() as! NSMutableArray
}
self.pickerView.reloadData()
}
func searchInArray(srchArray:NSMutableArray, withKey:String,Characters:String)->NSMutableArray
{
let resultArray=NSMutableArray()
for index in 0..<srchArray.count
{
let Dict = srchArray[index] as! [String:Any]
if let stringmatcher = Dict[withKey] as? String
{
if(stringmatcher.contains(find: Characters))
{
resultArray.add(Dict)
}
else
{
}
}
}
return resultArray
}
extension String {
func contains(find: String) -> Bool{
return self.range(of: find) != nil
}
And For Objective-C You have to Do something Like below. But don't forget to call textField Delegates.
NSMutableArray *filteredArray;
NSMutableArray *ArraywithFullData;
self.txtSearch.delegate=self
[self.txtSearch addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
//
-(void)textFieldValueChanged:(UITextField *)TextField
{
if((TextField.text.length)>0)
{
filteredArray = [self searchInArray:ArraywithFullData withKey:#"key value" andCharacters:TextField.text];
}
else
{
filteredArray = [ArraywithFullData mutableCopy];
}
[self.pickerView reloadData];
}
-(NSMutableArray *)searchInArray:(NSMutableArray*)srchArray withKey:(NSString *)key andCharacters:(NSString *)charecters
{
NSMutableArray *resultArray= [[NSMutableArray alloc]init];
for (int index=0 ; index<srchArray.count; index++)
{
NSMutableDictionary *Dict = srchArray[index];
if ([Dict valueForKey:key] != nil)
{
NSString * stringmatcher = [Dict valueForKey:key];
if ([stringmatcher containsString:charecters])
{
[resultArray addObject:Dict];
}
else
{
}
}
}
return resultArray;
}
Note if data is not in form of array of Dictionaries you can remove code work that is about dictionaries
Related
I have a name as "Ryan" and next time entering "Ryan" it should check it has the value,So it should make it "Ryan_1". The same way it should check if anytime someone added again "Ryan" it should change it to "Ryan_2".
Example:
nameArray = ["Ryan","John","Ryan_2","Rhonda","Ryan_3","Kylie","Ryan_4","John_2"];
I am using below code which is working fine while adding the name first time.
But when I am coming back to the section and editing value Ex: I changed Ryan_2 to "xyz" and again thought of keeping "Ryan" the saved value is becoming "Ryan_4" where as it supposed to be "Ryan_2" in the array. And let say if I am changing "Ryan_4" to "somenewName" now the numbering of other duplicate names also get rearranged.
NSMutableArray *array = [[NSMutableArray alloc]init];
int occurrences = 0;
for(NSString *string in nameArray) {
if ([value isKindOfClass:[NSString class]]) {
if ([string containsString:value]) {
[array addObject:string];
}
occurrences+= ([string containsString:value] ? 1 : 0);
}
}
if ([value isKindOfClass:[NSString class]]) {
if (![value isEqualToString:#""]) {
if (occurrences > 1) {
value = [value stringByAppendingFormat:#"_%d", occurrences];
}
}
}
I would recommend an extension like this:
extension NSMutableArray {
public func appendWithSuffix(strNewEntry:String) {
var n = 1
var new = strNewEntry
if self.containsObject(strNewEntry) {
new = strNewEntry + "_\(n)"
while self.containsObject( new ){
n += 1
new = strNewEntry + "_\(n)"
}
}
self.addObject( new )
}}
It will look for an exact match and insert if none is found, i.e it will add "Ryan_5" instead of "Ryan", "John_3" instead of "John" and so on.
Another approach may be to iterate thru all entries for comparison or filter the array with "namexy".hasPrefix("Ryan") to get max index of name to be inserted.
- (IBAction)SaveText:(id)sender
{
if (array.count==0)
{
[array addObject:_txtAddText.text];
}else
{
for(NSString *string in array)
{
if ([string containsString:_txtAddText.text] )
{
count = count+1;
NSString *Localstring =[NSString stringWithFormat:#"%#%d",[string stringByAppendingString:#"_"],count];
NSLog(#"%#",Localstring);
[array addObject:Localstring];
break;
}else
{
[array addObject:_txtAddText.text];
}
}
}
NSLog(#"%#",array);
}
I am using the ActionSheetStringPicker from the ActionSheetPickers3.0 (since I no longer can use the old picker views because of iOS 8). This is how I am calling the method:
ActionSheetStringPicker *genderPicker = [[ActionSheetStringPicker alloc]
initWithTitle:#"Gender" rows:categoryTypes initialSelection:nil target:self
successAction:#selector(selectedGender:) cancelAction:#selector(cancelledGender)
origin:gender];
[genderPicker showActionSheetPicker];
My success action code is this:
-(void) selectedGender:(NSNumber *)genderSelected {
NSLog(#"selected gender: %#",genderSelected);
if (genderSelected == 0) {
NSLog(#"male");
gender.text = #"Male";
} else {
NSLog(#"female");
gender.text = #"Female";
}
}
I am getting either a 1 or 0 value from the selected gender (male/female) when I NSLog the genderSelected value. My problem is that in my if-statement it always says I picked female. I'm getting the correct value that I select from the picker, but can't seem to figure out what the problem is. Does anyone know how I can get my if-statement working? Thanks!
In your success callback method the parameter you are getting is of type NSNumber. You cannot directly compare the object of type NSNumber with int value 0. Therefore use the following :
if (genderSelected.intValue == 0) {
NSLog(#"male");
gender.text = #"Male";
} else {
NSLog(#"female");
gender.text = #"Female";
}
Well this isn't exactly what I was looking for, but it worked. I set the NSNumber that I was getting as an NSString then compared to a "0" and "1" string. Here is my solution:
-(void) selectedGender:(NSNumber *)genderSelected {
NSString *string = [NSString stringWithFormat:#"%#",genderSelected];
if ([string isEqualToString:#"0"]) {
NSLog(#"male");
} else if ([string isEqualToString:#"1"]) {
NSLog(#"female");
}
}
when search value from array am getting <__NSArrayM:> was mutated while being enumerated. Am using this code.
NSInteger strlen=[searchText length];
for (NSString *pStr in pArrBusinessName ) {
NSRange nameRange = [pStr rangeOfString:searchText options:NSCaseInsensitivePredicateOption];
if(nameRange.location != NSNotFound) {
if (strlen == 1) {
pArrFilteredTableData = pArrBusinessName;
} else {
if ([pStr isKindOfClass:[NSNull class]]) {
NSLog(#"NSNull isKindOfClass called!");
}
if (![pStr isKindOfClass:[NSNull class]]) {
[pArrFilteredTableData addObject:pStr];
}
}
} else {
if ([pArrFilteredTableData count] == 0) {
}
}
[pTblDetails reloadData];
}
Change this code:
pArrFilteredTableData = pArrBusinessName;
To this;
pArrFilteredTableData = [pArrBusinessName mutableCopy];
make sure pArrFilteredTableData is a NSMutableArray if it wasn't already
It seems to be that you are doing modifications in the main array while searching the contents inside it. It would be good if you hold your search results in a separate mutable array rather than mutating the main array using which you created your list. Filter searched records from the main array and hold them in search array.
I have this Swift method that I want to convert to Objective-C. The method is using the extend method of Array and as far as I understand it just adds an object to the array while calling itself again.
Swift:
///the method to serialized all the objects
func serializeObject(object: AnyObject,key: String?) -> Array<HTTPPair> {
var collect = Array<HTTPPair>()
if let array = object as? Array<AnyObject> {
for nestedValue : AnyObject in array {
collect.extend(self.serializeObject(nestedValue,key: "\(key!)[]"))
}
} else if let dict = object as? Dictionary<String,AnyObject> {
for (nestedKey, nestedObject: AnyObject) in dict {
var newKey = key != nil ? "\(key!)[\(nestedKey)]" : nestedKey
collect.extend(self.serializeObject(nestedObject,key: newKey))
}
} else {
collect.append(HTTPPair(value: object, key: key))
}
return collect
}
What I've done so far in Objective-C.
- (NSArray*) serializeObject:(id)obj key:(NSString*)key
{
NSMutableArray* collect = [NSMutableArray array];
if ([obj isKindOfClass:[NSArray class]])
{
NSArray* objArray = obj;
if (obj)
{
for (id nestedObj in objArray)
{
[collect addObject:[self serializeObject:nestedObj key:[NSString stringWithFormat:#"%#[]", key]]];
}
}
}
else if ([obj isKindOfClass:[NSDictionary class]])
{
NSDictionary* dict = obj;
if (dict)
{
for (NSString* nestedKey in dict)
{
NSString* newKey = key != nil ? [NSString stringWithFormat:#"%#[%#]", key, nestedKey] : nestedKey;
id nestedObject = [dict objectForKey:newKey];
if (nestedObject)
{
[collect addObject:[self serializeObject:nestedObject key:newKey]];
}
}
}
}
else
{
[collect addObject:[[WEEHTTPPair alloc] initWithValue:obj andKey:key]];
}
return collect;
}
The goal is to get an NSArray of WEEHTTPPair objects for every key/value pair in the dictionary but I lose the meaning of extend and append to apply in my Objective-C code. For me it looks like both are adding the object to the array which is created new anyway but it's more that I lack in knowledge so far.
[EDIT]
The method is used accordingly.
Swift.
///convert the parameter dict to its HTTP string representation
func stringFromParameters(parameters: Dictionary<String,AnyObject>) -> String {
return join("&", map(serializeObject(parameters, key: nil), {(pair) in
return pair.stringValue()
}))
}
I converted to Objective-C borrowed BlockKits map extension.
Objective-C.
- (NSString*) stringFromParameters:(NSDictionary*)parameters
{
WEENSArrayBlocksKit* blockKit = [WEENSArrayBlocksKit new];
NSArray* serializedParams = [self serializeObject:parameters key:nil];
NSArray* arrayParams = [blockKit bk_map:serializedParams withBlock:^id(id obj)
{
// obj is an array without the desired results
WEEHTTPPair* httpPair = obj;
NSString* stringValue = nil;
if (httpPair)
{
stringValue = [httpPair stringValue];
}
return stringValue;
}];
NSString* joinedString = [arrayParams componentsJoinedByString:#"&"];
return joinedString;
}
When you do this:
[collect addObject:[self serializeObject:nestedObject key:newKey]];
You are adding an NSArray to your collect object. Instead, you want to add the objects contained within the response to collect:
[collect addObjectsFromArray:[self serializeObject:nestedObject key:newKey]];
I have a dictionary that contains events. The format for one event looks like this
{
eventTime = 53';
eventType = "Yellow Card";
gameID = 0;
name = Mike;
selectedTeam = homeTeam;
}
And i have saved all of the events into an NSMutableArray. The clients will insert events as the time goes (for a soccer game). Now i need to check when populating my UITableView if a player has got two yellow cards so i can change the image to a different image. The way I'm doing it now looks like this and i don't really like it and it does not really work.
if ([typeEvent isEqualToString:#"Yellow Card"]){
int i= 0;
for (id obj in _events)
{
if ([[obj valueForKeyPath:[NSString stringWithFormat:#"eventType"]] isEqualToString:#"Yellow Card"] && [[obj valueForKeyPath:[NSString stringWithFormat:#"name"]] isEqualToString:[gameInfoObject valueForKeyPath:[NSString stringWithFormat:#"name"]]] ) {
i++;
if (i >= 2) {
imageType = [UIImage imageNamed:#"Yellow&Red.png"];
}
}
}
}
and in my UITableView i do this so you know what is what in the code above
NSMutableDictionary *gameInfoObject =[_events objectAtIndex:indexPath.row];
So basically if there is more than 1 event in EVENTS array where the eventType equals "Yellow Card" and the name of those matches i need to change the image to "Yellow&Red"
Thank you for you help
I would start by using one of the fast enumerator methods provided by NSArray.
NSIndexSet *matchingSet = [_events indexesOfObjectsPassingTest:^BOOL(id obj,
NSUInteger idx,
BOOL *stop){
return ([gameInfoObject[#"name"] isEqualToString:obj[#"name"] && [obj[#"eventType"] isEqualToString:#"Yellow Card"])
}];
if (matchingSet.count >= 2) {
imageType = [UIImage imageNamed:#"Yellow&Red.png"];
}
Look into using an NSCountedSet for your objects. You'll get a constant time lookup and a count.
You could do this in a few different ways. Personally, I think that having an event object is going to be the most readable for your code, but if you want to use simple objects like NSArray and NSDictionary, you could solve this easily with two extra NSMutableArrays or one extra NSMutableDictionary or one extra NSCountedSet.
NSMutableSets:
NSMutableSet *yellowCardPlayers;
NSMutableSet *redCardPlayers;
- (void)receiveEvent:(NSDictionary *)event {
[_events addObject:event];
if ([event[#"eventType"] isEqualToString:#"Yellow Card"]) {
if ([yellowCardPlayers containsObject:event[#"name"]]) {
if ([redCardPlayers containsObject:event[#"name"]]) {
// How did a player get a yellow card after already being ejected from the game?! :)
} else {
[redCardPlayers addObject:event[#"name"]];
}
} else {
[yellowCardPlayers addObject:event[#"name"]];
}
}
}
NSMutableDictionary:
NSMutableDictionary *playerYellowCards;
- (void)receiveEvent:(NSDictionary *)event {
[_events addObject:event];
if ([event[#"eventType"] isEqualToString:#"Yellow Card"]) {
NSNumber *numberOfYellowCards = [playerYellowCards objectForKey:event[#"name"]];
if (![[playerYellowCards allKeys] containsObject:event[#"name"]]) {
[playerYellowCards addObject:#(1) forKey:event[#"name"]];
} else {
[playerYellowCards addObject:#([playerYellowCards[event[#"name"]] integerValue]+1) forKey:event[#"name"]];
}
}
}
NSCountedSet:
NSCountedSet *playerYellowCards;
- (void)receiveEvent:(NSDictionary *)event {
[_events addObject:event];
if ([event[#"eventType"] isEqualToString:#"Yellow Card"]) {
[playerYellowCards addObject:event[#"name"]];
}
}
Use NSPredicate to filter your array, and then count the results:
NSPredicate *yellowFlagFilter = [NSPredicate predicateWithFormat:#"eventType == %# AND name == %#",#"Yellow Card", gameInfoObject.name];
NSArray *yellowCards = [_events filteredArrayUsingPredicate:yellowFlagFilter];
if ([yellowCards count] > 1) {
imageType = [UIImage imageNamed:#"Yellow&Red.png"];
}