SOAP in iOS - Extracting multiple strings from XML - objective-c

In an iOS program I am making, I am requesting a list of courses with SOAP. This is the reply format
<ListCoursesResponse>
<statusMessage xmlns="xxx">string</statusMessage>
<courseID xmlns="xxx">string</courseID>
<courseTitle xmlns="xxx">string</courseTitle>
</ListCoursesResponse>
<ListCoursesResponse>
<statusMessage xmlns="xxx">string</statusMessage>
<courseID xmlns="xxx">string</courseID>
<courseTitle xmlns="xxx">string</courseTitle>
</ListCoursesResponse>
I am using something along the lines of extrating each separate course as an element in an array, than stepping through the array for each and extracting what is between the Course ID. However, I can't figure out how to extract more than one, as when I return it, it only shows the first course. If I explained this in a bad way, please do tell me so I can try to explain better.
My question is, what's the best way to approach a large list of courses (200+) returned in an XML reponse ?
Edit: Snippet of the code I am using, which only returns 1 ID.
NSString *tag1Open = #"<ListCoursesResponse>";
NSString *tag1Close = #"</ListCoursesResponse>";
NSString *courseIDOpen = #"<courseID xmlns=\"http://drm.mediuscorp.com/\">";
NSString *courseIDClose = #"</courseID>";
result = #"";
NSArray *XMLarray1 = [XMLResult componentsSeparatedByString:tag1Open];
if ([XMLarray1 count] > 1) {
for (int i = 0; i < [XMLarray1 count]; i++) {
NSString *courseIDString = [[[XMLarray1 objectAtIndex:1]componentsSeparatedByString:tag1Close]objectAtIndex:0];
NSArray *courseID = [XMLResult componentsSeparatedByString:courseIDOpen];
if ([courseID count] > 1) {
for (int i = 0; i < [courseID count]; i++) {
courseIDString = [[[courseID objectAtIndex:1]componentsSeparatedByString:courseIDClose]objectAtIndex:0];
}
}
NSLog(#"Course ID: %#",courseIDString);
}
[persArray addObject:result];
for (int i = 0; i < [persArray count]; i++) {
NSLog(#"%#",[persArray objectAtIndex:i]);
}
}

Rather than try to parse the SOAP XML response response yourself using NSString methods, you would be much better off using an XML Parser to handle this task. iOS has a built-in XML Parser called NSXMLParser that is available to you. (There are also numerous third-party XML Parser components available, of both SAX and DOM varieties)
Here is a tutorial that gives an example of using NSXMLParser.

Related

Calculating value of K without messages

Question:
Find the value of K in myInterViewArray without any messages/calls
I was given this hint:
The numbers in the array will never exceed 1-9.
NSArray *myInterViewArray = #[#2,#1,#3,#9,#9,#8,#7];
Example:
If you send 3, the array will return the 3 biggest values in myInterViewArray * 3. So in the example below, K = 9 + 9 + 8.
--
I was asked this question a while back in an interview and was completely stumped. The first solution that I could think of looked something like this:
Interview Test Array:
[self findingK:myInterViewArray abc:3];
-(int)findingK:(NSArray *)myArray abc:(int)k{ // With Reverse Object Enumerator
myArray = [[[myArray sortedArrayUsingSelector:#selector(compare:)] reverseObjectEnumerator] allObjects];
int tempA = 0;
for (int i = 0; i < k; i++) {
tempA += [[myArray objectAtIndex:i] intValue];
}
k = tempA;
return k;
}
But apparently that was a big no-no. They wanted me to find the value of K without using any messages. That means that I was unable to use sortedArrayUsingSelector and even reverseObjectEnumerator.
Now to the point!
I've been thinking about this for quite a while and I still can't think of an approach without messages. Does anyone have any ideas?
There is only one way to do that and that is bridging the array to CF type and then use plain C, e.g.:
NSArray *array = #[#1, #2, #3];
CFArrayRef cfArray = (__bridge CFArrayRef)(array);
NSLog(#"%#", CFArrayGetValueAtIndex(cfArray, 0));
However, if the value is a NSNumber, you will still need messages to access its numeric value.
Most likely the authors of the question didn't have a very good knowledge of the concept of messages. Maybe they thought that subscripting and property access were not messages or something else.
Using objects in Obj-C without messages is impossible. Every property access, every method call, every method initialization is done using messages.
Rereading the question, they probably wanted you to implement the algorithm without using library functions, e.g. sort (e.g. you could implement a K-heap and use that heap to find the K highest numbers in a for iteration).
I assume what is meant is that you can't mutate the original array. Otherwise, that restriction doesn't make sense.
Here's something that might work:
NSMutableArray *a = [NSMutableArray array];
for (NSNumber *num in array) {
BOOL shouldAdd = NO;
for (int i = a.count - 1; i >= k; i--) {
if ([a[i] intValue] < [num intValue]) {
shouldAdd = YES;
break;
}
}
if (shouldAdd) {
[a addObject:num];
}
}
int result = a[a.count - k];
for (int i = k; k < a.count; k++) {
result += [a[i] intValue];
}
return result;

Converting a string variable from Binary to Decimal in Objective C

Im trying to create a Binary to Decimal calculator and I am having trouble doing any sort of conversion that will actually work. First off Id like to introduce myself as a complete novice to objective c and to programming in general. As a result many concepts will appear difficult to me, so I am mostly looking for the easiest way to understand and not the most efficient way of doing this.
I have at the moment a calculator that will accept input and display this in a label. This part is working fine and I have no issues with it. The variable that the input is stored on is _display = [[NSMutableString stringWithCapacity:20] retain];
this is working perfectly and I am able to modify the data accordingly. What I would like to do is to be able to display an NSString of the conversion in another label. At the moment I have tried a few solutions and have not had any decent results, this is the latest attempt
- (NSMutableString *)displayValue2:(long long)element
{
_str= [[NSMutableString alloc] initWithString:#""];
if(element > 0){
for(NSInteger numberCopy = element; numberCopy > 0; numberCopy >>= 1)
{
[_str insertString:((numberCopy & 1) ? #"1" : #"0") atIndex:0];
}
}
else if(element == 0)
{
[_str insertString:#"0" atIndex:0];
}
else
{
element = element * (-1);
_str = [self displayValue2:element];
[_str insertString:#"0" atIndex:0];
NSLog(#"Prima for: %#",_str);
for(int i=0; i<[_str length];i++)
_str = _display;
NSLog(#"Dopo for: %#",_str);
}
return _str;
}
Within my View Controller I have a convert button setup, when this is pressed I want to set the second display field to the decimal equivalent. This is working as if I set displayValue2 to return a string of my choosing it works. All I need is help getting this conversion to work. At the moment this bit of code has led to "incomplete implementation" being displayed at the to of my class. Please help, and cheers to those who take time out to help.
So basically all you are really looking for is a way to convert binary numbers into decimal numbers, correct? Another way to think of this problem is changing a number's base from base 2 to base 10. I have used functions like this before in my projects:
+ (NSNumber *)convertBinaryStringToDecimalNumber:(NSString *)binaryString {
NSUInteger totalValue = 0;
for (int i = 0; i < binaryString.length; i++) {
totalValue += (int)([binaryString characterAtIndex:(binaryString.length - 1 - i)] - 48) * pow(2, i);
}
return #(totalValue);
}
Obviously this is accessing the binary as a string representation. This works well since you can easily access each value over a number which is more difficult. You could also easily change the return type from an NSNumber to some string literal. This also works for your element == 0 scenario.
// original number wrapped as a string
NSString *stringValue = [NSString stringWithFormat:#"%d", 11001];
// convert the value and get an NSNumber back
NSNumber *result = [self.class convertBinaryStringToDecinalNumber:stringValue];
// prints 25
NSLog(#"%#", result);
If I misunderstood something please clarify, if you do not understand the code let me know. Also, this may not be the most efficient but it is simple and clean.
I also strongly agree with Hot Licks comment. If you are truly interested in learning well and want to be an developed programmer there are a few basics you should be learning first (I learned with Java and am glad that I did).

UICollection View images from url

I have followed this tutorial to make a UICollectionView custom layout: http://skeuo.com/uicollectionview-custom-layout-tutorial#section4
I got through it and I got it working. But when I try to use it with my own pictures I cannot get them show in the app.
Here's the code to get the pictures
self.albums = [NSMutableArray array];
NSURL *urlPrefix =
[NSURL URLWithString:#"https://raw.github.com/ShadoFlameX/PhotoCollectionView/master/Photos/"];
NSInteger photoIndex = 0;
for (NSInteger a = 0; a < 12; a++) {
BHAlbum *album = [[BHAlbum alloc] init];
album.name = [NSString stringWithFormat:#"Photo Album %d",a + 1];
NSUInteger photoCount = 1;
for (NSInteger p = 0; p < photoCount; p++) {
// there are up to 25 photos available to load from the code repository
NSString *photoFilename = [NSString stringWithFormat:#"thumbnail%d.jpg",photoIndex % 25];
NSURL *photoURL = [urlPrefix URLByAppendingPathComponent:photoFilename];
BHPhoto *photo = [BHPhoto photoWithImageURL:photoURL];
[album addPhoto:photo];
photoIndex++;
}
[self.albums addObject:album];
}
So the problem comes when I change the url string to the one with my pictures. I want to use a public website for hosting images like Flickr, but I also tried Imageshak.us and postimage.org and it didn't work.
I have the photo names as it says the string: thumbnail%d.jpd so that is not the problem. Any ideas?
UPDATE:
I tried using this
[NSURL URLWithString:#"http://www.flickr.com/photos/93436974#N06/"];
That's the url to the gallery, but it doesn't show anything. If I can't use Flickr, is there any other websites similar that could be used?
For your thumbnails you're naming them "thumbnail0.jpg" "thumbnail1.jpg" etc right? The %d means insert the number from outside the quotes here, for the code you posted it takes whichever number photo you're on and adds it into your string (up to a maximum of 25 at which point it will restart , ie photo 27 would return thumbnail2.jpg
Just quickly googling it looks like flickr doesn't keep the source file name so it wouldn't work with the code you posted. I would recommend photobucket I beilieve they keep the source file name and urls are easy to work with

adding a string followed by an int to an array

I am very new to Objective-C with Cocoa, and I need help.
I have a for statement in which I loop i from 1 to 18, and I would like to add an object to an NSMutableArray in this loop. Right now I have:
chapterList = [[NSMutableArray alloc] initWithCapacity:18];
for (int i = 1; i<19; i++)
{
[chapterList addObject:#"Chapter"+ i];
}
I would like it to add the objects, chapter 1, chapter 2, chapter 3... , chapter 18. I have no idea how to do this, or even if it is possible. Is there a better way? Please Help
Thanks in advance,
chapterList = [[NSMutableArray alloc] initWithCapacity:18];
for (int i = 1; i<19; i++)
{
[chapterList addObject:[NSString stringWithFormat:#"Chapter %d",i]];
}
good luck
Try:
[chapterList addObject:[NSString stringWithFormat:#"Chapter %d", i]];
In Objective-C/Cocoa you can't append to a string using the + operator. You either have to use things like stringWithFormat: to build the complete string that you want, or things like stringByAppendingString: to append data to an existing string. The NSString reference might be a useful place to start.
If you're wanting strings that merely say Chapter 1, Chapter 2, you can just do this:
chapterList = [[NSMutableArray alloc] initWithCapacity:18];
for (int i = 1; i<19; i++) {
[chapterList addObject:[NSString stringWithFormat:#"Chapter %d",i]];
}
And don't forget to release the array when you're done, as you're calling alloc on it.

How do I traverse a multi dimensional NSArray?

I have array made from JSON response.
NSLog(#"%#", arrayFromString) gives the following:
{
meta = {
code = 200;
};
response = {
groups = (
{
items = (
{
categories = (
{
icon =
"http://foursquare.com/img/categories/parks_outdoors/default.png";
id = 4bf58dd8d48988d163941735;
and so on...
This code
NSArray *arr = [NSArray arrayWithObject:[arrayFromString valueForKeyPath:#"response.groups.items"]];
gives array with just one element that I cannot iterate through. But if I write it out using NSLog I can see all elements of it.
At the end I would like to have an array of items that I can iterate through to build a datasource for table view for my iPhone app.
How would I accomplish this?
EDIT:
I have resolved my issue by getting values from the nested array (objectAtIndex:0):
for(NSDictionary *ar in [[arrayFromString valueForKeyPath:#"response.groups.items"] objectAtIndex:0]) {
NSLog(#"Array: %#", [ar objectForKey:#"name"]);
}
First, the data structure you get back from the JSON parser is not an array but a dictionary: { key = value; ... } (curly braces).
Second, if you want to access a nested structure like the items, you need to use NSObject's valueForKeyPath: method. This will return an array of all items in your data structure:
NSLog(#"items: %#", [arrayFromString valueForKeyPath:#"response.groups.items"]);
Note that you will loose the notion of groups when retrieving the item objects like this.
Looking at the JSON string you posted, response.groups.items looks to be an array containing one item, a map/dictionary containing one key, "categories." Logging it out to a string is going to traverse the whole tree, but to access it programmatically, you have to walk the tree yourself. Without seeing a more complete example of the JSON, it's hard to say exactly what the right thing to do is here.
EDIT:
Traversing an object graph like this is not that simple; there are multiple different approaches (depth-first, breadth-first, etc,) so it's not necessarily something for which there's going to be a simple API for you to use. I'm not sure if this is the same JSON library that you're using, but, for instance, this is the code from a JSON library that does the work of generating the string that you're seeing. As you can see, it's a bit involved -- certainly not a one-liner or anything.
You could try this, which I present without testing or warranty:
void __Traverse(id object, NSUInteger depth)
{
NSMutableString* indent = [NSMutableString string];
for (NSUInteger i = 0; i < depth; i++) [indent appendString: #"\t"];
id nextObject = nil;
if ([object isKindOfClass: [NSDictionary class]])
{
NSLog(#"%#Dictionary {", indent);
NSEnumerator* keys = [(NSDictionary*)object keyEnumerator];
while (nextObject = [keys nextObject])
{
NSLog(#"%#\tKey: %# Value: ", indent, nextObject);
__Traverse([(NSDictionary*)object objectForKey: nextObject], depth+1);
}
NSLog(#"%#}", indent);
}
else if ([object isKindOfClass: [NSArray class]])
{
NSEnumerator* objects = [(NSArray*)object objectEnumerator];
NSLog(#"%#Array (", indent);
while (nextObject = [objects nextObject])
{
__Traverse(nextObject, depth+1);
}
NSLog(#"%#)", indent);
}
else
{
NSLog(#"%#%#",indent, object);
}
}
void Traverse(id object)
{
__Traverse(object, 0);
}