Add contents of an IBoutletcollection to an array? - objective-c

I have two IBoutletcollections called numbers and symbols. I want to add the contents of their title in an array such that the first element of the array is from numbers and second from symbols, third from numbers, fourth from symbols and so on.
Is there a way to do it?
EDIT:
//#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray symbols;
//#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *numbers;
-(void)setNumbers:(NSArray *)numbers
{
_numbers=numbers;
for (UIButton button in self.numbers)
{
Number * number = [[Number alloc]init];
[button setTitle:[number randnum] forState:UIControlStateNormal];
}
}
This is the code for setting the title of the outlet collection numbers.

Here you go, assuming your IBOutletCollections contain elements of class UILabel and have the same number of elements:
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *numbers;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *symbols;
NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:self.numbers.count+self.symbols.count];
for (int i = 0; i < self.numbers.count+self.symbols.count; i++) {
if (i%2 == 0) {
[result addObject:((UIButton *)self.numbers[i]).titleLabel.text];
}
else{
[result addObject:((UIButton *)self.symbols[i]).titleLabel.text];
}
}
The solution to your problem is to run a loop and in the loop do a modulo calculation with 2 to find out when you have an even or odd position in the result array, and then add the element from the appropriate IBOutletCollection. Is this clear?

Related

How to access view's subviews without crash while hooking Swift? (Jailbreak)

I have an odd issue where when I change the background of a view, I can no longer see the UILabels that are subviews of that view. I cannot dump the headers for the Calculator app, as it is in Swift, and I don't know what the name of the UILabels are, and FLEXing is no help with that. I want to bring the subviews in front of the background view (there are two subviews), but both of my current methods crash the target app. I was trying to see if I could get it working with just one at the very front though.
My code:
NSMutableArray *labels = [NSMutableArray arrayWithArray:((DisplayView*)self).allSubviews];
if ([labels count] > 0) {
UILabel *mainLabel = labels[0];
[self bringSubviewToFront:mainLabel];
}
((DisplayView*)self).allSubviews = labels;
And I have also tried:
for (UILabel *label in ((DisplayView*)self).allSubviews) {
if ([label isKindOfClass:[UILabel class]]) {
[self bringSubviewToFront:label];
}
I need an alternative method of doing this, a way to bring all of the subviews forward, or someone to tell me what I am doing wrong.
Edit, here's my full code:
#interface DisplayView
#property (nonatomic, copy, readwrite) UIColor *backgroundColor;
#property (nonatomic, assign, readwrite, getter=isHidden) BOOL hidden;
#property (nonatomic, assign, readwrite, getter=isOpaque) BOOL opaque;
#property (nonatomic, assign, readwrite) CGFloat alpha;
#property (nonatomic, copy, readwrite) NSArray *allSubviews;
#property (nonatomic, assign, readwrite) CALayer *layer;
#end
%hook DisplayView
-(void)layoutSubviews {
((DisplayView*)self).opaque = NO;
((DisplayView*)self).backgroundColor = [UIColor blackColor];
((DisplayView*)self).hidden = NO;
((DisplayView*)self).alpha = 1.0;
NSMutableArray *labels = [NSMutableArray arrayWithArray:((DisplayView*)self).layer.sublayers];
if ([labels count] > 0) {
UILabel *mainLabel = labels[0];
[self bringSubviewToFront:mainLabel];
}
}
%end
%ctor {
%init(DisplayView=objc_getClass("Calculator.DisplayView"));
}
Seems like a few possible issues. First, there is no allSubviews on UIView, it probably should be subviews.
NSMutableArray *labels = [NSMutableArray arrayWithArray:((DisplayView*)self).subviews];
if ([labels count] > 0) {
UILabel *mainLabel = labels[0];
(Just want point out that you don't seem to change the array, so why copy it? You can directly access self.subviews)
Second, in the CALayer version, you're casting CALayer to UIView:
NSMutableArray *labels = [NSMutableArray arrayWithArray:((DisplayView*)self).layer.sublayers];
CALayer *mainLabel = labels.firstObject;
if (mainLabel) {
[labels removeObjectAtIndex:0];
[labels addObject:mainLabel];
self.layer.sublayers = labels;
}
Maybe some of this helps

Loop over an array of UIButtons in Objective-C

I have an array of buttons which I want to change some properties in all of them.
The array is like this:
NSArray *buttons = #[_smallButton, _mediumButton, _largeButton, _xlargeButton];
The buttons are outlets:
#property (weak, nonatomic) IBOutlet UIButton *smallButton;
#property (weak, nonatomic) IBOutlet UIButton *mediumButton;
#property (weak, nonatomic) IBOutlet UIButton *largeButton;
#property (weak, nonatomic) IBOutlet UIButton *xlargeButton;
Now I want to change all borderColors and set tag for each in a loop over the array:
for(int i=0; i< buttons.count; i++) {
[buttons[i] layer].borderColor = [UIColor darkGrayColor].CGColor;
[buttons[i] setTag:i];
}
The point is that the setTag works fine and gets applied to all buttons but the borderColor is only changed for the first item, not all of them.
Does anybody know what I've missed?
Try to set a borderWidth and a cornerRadius to all of them, i.e.:
for(int i=0; i< buttons.count; i++) {
[buttons[i] layer].borderColor = [UIColor darkGrayColor].CGColor;
[buttons[i] layer].borderWidth = 1;
[buttons[i] layer].cornerRadius = 4;
[buttons[i] setTag:i];
}

Unable to add string into an mutable array

I am trying to upload assignments into a table in an different view controller. First when i click on the upload button this code runs.
- (IBAction)uploadAssignment:(id)sender {
nameOfAssignmentAsString = self.nameOfAssignment.text;
NSLog(#"%#", nameOfAssignmentAsString);
NSInteger row;
row = [self.subjectPicker selectedRowInComponent:0];
subjectOfAssignmentAsString = [subjectArray objectAtIndex:row];
NSLog(#"%#", subjectOfAssignmentAsString);
NSDate *deadline = [self.deadlinePicker date];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"dd/MM/yyyy"];
deadlineOfAssignmentAsString = [dateFormat stringFromDate:deadline];
NSLog(#"%#",deadlineOfAssignmentAsString);
HomeworkViewController *HVC;
[HVC.nameOfAssignmentInAnArray addObject:nameOfAssignmentAsString];
[HVC.SubjectOfAssignmentInAnArray addObject:subjectOfAssignmentAsString];
[HVC.deadlineOfAssignmentInAnArray addObject:deadlineOfAssignmentAsString];
NSLog(#"%#",HVC.nameOfAssignmentInAnArray.count);
}
then in my HomeworkViewController.h this is the code
#interface HomeworkViewController : UIViewController <UIGestureRecognizerDelegate,UITableViewDataSource,UITableViewDelegate> {
int i;
}
#property (strong, nonatomic) IBOutlet UIView *mainMenu;
#property (strong, nonatomic) IBOutlet UIButton *homeworkButton;
#property (strong, nonatomic) IBOutlet UIButton *uploadButton;
#property (strong, nonatomic) NSMutableArray *nameOfAssignmentInAnArray;
#property (strong, nonatomic) NSMutableArray *SubjectOfAssignmentInAnArray;
#property (strong, nonatomic) NSMutableArray *deadlineOfAssignmentInAnArray;
I did initialise it in my HomeworkViewController.m file. But for some reason the string is not being added into the array.
You declare HVC but never assign a value to it. Therefore it cannot hold anything in itself. But for some reason the designers of Objective-C decided it's not an error to send messages to nil objects, so this might not be noticed.

ObjC get property name

I've looking for a way to get a property name as StringValue from inside a method.
Lets say:
My class has X Subviews from the Type UILabel.
#property (strong, nonatomic) UILabel *firstLabel;
#property (strong, nonatomic) UILabel *secondLabel;
[...]
and so on.
Inside the method foo, the views are iterated as followed:
-(void) foo
{
for (UIView *view in self.subviews) {
if( [view isKindOfClass:[UILabel class]] ) {
/*
codeblock that gets the property name.
*/
}
}
}
The Result should be something like that:
THE propertyName(NSString) OF view(UILabel) IS "firstLabel"
I've tried class_getInstanceVariable, object_getIvar and property_getName without Success.
For example, the code for:
[...]
property_getName((void*)&view)
[...]
Returns:
<UILabel: 0x6b768c0; frame = (65 375; 219 21); text = 'Something'; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x6b76930>>
But i'm looking for this kind of result: "firstLabel" , "secondLabel" and so on.
Solved
As in the Reply of graver described the solution is:
class_copyIvarList which returns the name of the Ivars.
Ivar* ivars = class_copyIvarList(clazz, &count);
NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count];
for (int i = 0; i < count ; i++)
{
const char* ivarName = ivar_getName(ivars[i]);
[ivarArray addObject:[NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding]];
}
free(ivars);
See posts:
https://stackoverflow.com/a/2302808/1228534
and
Objective C Introspection/Reflection
untested code from Getting an array of properties for an object in Objective-C
id currentClass = [self class];
NSString *propertyName;
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(currentClass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
propertyName = [NSString stringWithCString:property_getName(property)];
NSLog#("The propertyName is %#",propertyName);
}
Easy way to get a specific property name without running a loop
Lets say custom object is like below
#interface StoreLocation : NSObject
#property (nonatomic, strong) NSString *city;
#property (nonatomic, strong) NSNumber *lat;
#property (nonatomic, strong) NSNumber *lon;
#property (nonatomic, strong) NSString *street;
#property (nonatomic, strong) NSString *state;
#property (nonatomic, strong) NSString *code;
#end
#interface AppleStore : NSObject
#property (nonatomic, strong) StoreLocation *storeLocation;
#end
Below Objective macros will get the desired result
#define propertyKeyPath(property) (#""#property)
#define propertyKeyPathLastComponent(property) [[(#""#property)componentsSeparatedByString:#"."] lastObject]
Use the code below to get property name
NSLog(#"%#", propertyKeyPath(appleStore.storeLocation)); //appleStore.storeLocation
NSLog(#"%#", propertyKeyPath(appleStore.storeLocation.street)); //appleStore.storeLocation.street
NSLog(#"%#", propertyKeyPathLastComponent(appleStore.storeLocation)); //storeLocation
NSLog(#"%#", propertyKeyPathLastComponent(appleStore.storeLocation.street)); //street
Source : http://www.g8production.com/post/78429904103/get-property-name-as-string-without-using-the-runtime

Gaining access to an NSMutableArray

I am new to arrays and objects. I have a class HowToPlay.h (of course that has a .m also) their i define two arrays
NSMutableArray *nibs;
NSMutableArray *unusedNibs;
#property (nonatomic, retain) NSMutableArray *nibs;
#property (nonatomic, retain) NSMutableArray *unusedNibs;
then we jump into the .m,
i write all the stuff for the arrays,
nibs = [[NSMutableArray alloc]initWithObjects:#"Question 2", #"Question 3", nil];
self.unusedNibs = nibs;
[nibs release];
Then i also have another class called Question 1, i need to be able to use this array in that class, and be able to change it, but keep the changes on the HowToPlay.m file.
here is why, basically this array loads random NIB files, and then deletes them from the array when they have been used.
in Question 1.m here is what im doing to use the array
random = arc4random() % [self.unusedNibs count];
NSString *nibName = [self.unusedNibs objectAtIndex:random];
[self.unusedNibs removeObjectAtIndex:random];
if (nibName == #"Question 3") {
Question_3 *Q3 = [[Question_3 alloc] initWithNibName:#"Question 3" bundle:nil];
Q3.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:Q3 animated:YES];
[Q3 release];
}
if (nibName == #"Question 2") {
Question_2 *Q2 = [[Question_2 alloc] initWithNibName:#"Question 2" bundle:nil];
Q2.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:Q2 animated:YES];
[Q2 release];
}
This all seems to work fine, but the problem im having is it seems that objects in the array are not getting deleted, even though this line runs
[self.unusedNibs removeObjectAtIndex:random];
I haved tried making it
[HowToPlay.unusedNibs removeObjectAtIndex:random];
I get a error saying expected '.' before '.' token
It seems to me that i have access to read the array, but not to change it. any way to fix this so i can change the array? thanks
UPDATE:
here is the whole HowToPlay.h file contents:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
int score;
int usedQ1;
int usedQ2;
int usedQ3;
NSMutableArray *nibs;
NSMutableArray *unusedNibs;
#interface HowToPlay : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
UIPickerView *selectType;
NSMutableArray *selectArray;
AVAudioPlayer *audioPlayer;
UIActivityIndicatorView *progress;
UIButton *worldButton;
UIButton *politicsButton;
UIButton *starButton;
}
#property (nonatomic, retain) NSMutableArray *nibs;
#property (nonatomic, retain) NSMutableArray *unusedNibs;
#property (nonatomic, retain) IBOutlet UIButton *worldButton;
#property (nonatomic, retain) IBOutlet UIButton *politicsButton;
#property (nonatomic, retain) IBOutlet UIButton *starButton;
#property (nonatomic, retain) IBOutlet UIPickerView *selectType;
#property (nonatomic) int usedQ1;
#property (nonatomic) int usedQ2;
#property (nonatomic) int usedQ3;
#property (readwrite) int score;
-(IBAction)World:(id)sender;
- (IBAction)Politics:(id)sender;
-(IBAction)Stars:(id)sender;
#end
#import "MainViewController.h"
#import "Question 1.h"
#import "Question 2.h"
#import "Question 3.h"
I import after because otherwise i get errors
Also I have the array set up on theViewDidLoad part of HowToPlay, is this a bad idea?
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
NSURL *click = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/click.wav", [[NSBundle mainBundle] resourcePath]]];
audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:click error:nil];
audioPlayer.numberOfLoops = 1;
progress = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
progress.frame = CGRectMake(0.0, 0.0, 30.0, 30.0);
progress.center = self.view.center;
[self.view addSubview: progress];
usedQ1 = 0;
usedQ2 = 0;
usedQ3 = 0;
selectArray = [[NSMutableArray alloc]init];
[selectArray addObject:#"World"];
[selectArray addObject:#"Politics"];
[selectArray addObject:#"Stars"];
score = 0;
nibs = [[NSMutableArray alloc]initWithObjects:#"Question 2", #"Question 3", nil];
self.unusedNibs = nibs;
[nibs release];
}
How do you check if objects are actually deleted? Please post some more code as the way you remove objects from unusedNibs seems to be fine. As per this code:
[self.unusedNibs removeObjectAtIndex:random];
and this code
[HowToPlay.unusedNibs removeObjectAtIndex:random];
The reason why you're getting this error is because you're trying to access unusedNibs using a class name "HowToPlay" instead of its instance "self".
A couple of things: first, to call properties like unusedNibs in HowToPlay it looks like you are calling the class and not an instance. You need to create a HowToPlay object and assign it to a property in your Question1 object so the question one Object has something to call to. Question1 should not call 'self' for unusedNibs since it does not own it.
With what you are doing it might make more sense to put the function figuring out the next random controller in the HowToPlay class. That way your question view controllers could just ask it to return which controller is next without having to duplicate that code across every question controller.